Skip to content

Commit 3de85c9

Browse files
author
Savannah Norem
authored
Merge branch 'main' into limit_return_fields
2 parents 79e6140 + c5068e5 commit 3de85c9

File tree

7 files changed

+579
-36
lines changed

7 files changed

+579
-36
lines changed

.github/workflows/spellcheck.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
- name: Checkout
99
uses: actions/checkout@v4
1010
- name: Check Spelling
11-
uses: rojopolis/spellcheck-github-actions@0.36.0
11+
uses: rojopolis/spellcheck-github-actions@0.40.0
1212
with:
1313
config_path: .github/spellcheck-settings.yml
1414
task_name: Markdown

aredis_om/model/encoders.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def jsonable_encoder(
9090
sqlalchemy_safe=sqlalchemy_safe,
9191
)
9292
if dataclasses.is_dataclass(obj):
93-
return dataclasses.asdict(obj)
93+
return dataclasses.asdict(obj) # type: ignore[call-overload]
9494
if isinstance(obj, Enum):
9595
return obj.value
9696
if isinstance(obj, PurePath):

aredis_om/model/model.py

+41-17
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
ClassVar,
1515
Dict,
1616
List,
17+
Literal,
1718
Mapping,
1819
Optional,
1920
Sequence,
@@ -141,10 +142,10 @@ def embedded(cls):
141142

142143
def is_supported_container_type(typ: Optional[type]) -> bool:
143144
# TODO: Wait, why don't we support indexing sets?
144-
if typ == list or typ == tuple:
145+
if typ == list or typ == tuple or typ == Literal:
145146
return True
146147
unwrapped = get_origin(typ)
147-
return unwrapped == list or unwrapped == tuple
148+
return unwrapped == list or unwrapped == tuple or unwrapped == Literal
148149

149150

150151
def validate_model_fields(model: Type["RedisModel"], field_values: Dict[str, Any]):
@@ -889,7 +890,9 @@ def resolve_redisearch_query(cls, expression: ExpressionOrNegated) -> str:
889890

890891
return result
891892

892-
async def execute(self, exhaust_results=True, return_raw_result=False):
893+
async def execute(
894+
self, exhaust_results=True, return_raw_result=False, return_query_args=False
895+
):
893896
args: List[Union[str, bytes]] = [
894897
"FT.SEARCH",
895898
self.model.Meta.index_name,
@@ -914,6 +917,9 @@ async def execute(self, exhaust_results=True, return_raw_result=False):
914917
if self.nocontent:
915918
args.append("NOCONTENT")
916919

920+
if return_query_args:
921+
return self.model.Meta.index_name, args
922+
917923
# Reset the cache if we're executing from offset 0.
918924
if self.offset == 0:
919925
self._model_cache.clear()
@@ -947,6 +953,10 @@ async def execute(self, exhaust_results=True, return_raw_result=False):
947953
self._model_cache += _results
948954
return self._model_cache
949955

956+
async def get_query(self):
957+
query = self.copy()
958+
return await query.execute(return_query_args=True)
959+
950960
async def first(self):
951961
query = self.copy(offset=0, limit=1, sort_fields=self.sort_fields)
952962
results = await query.execute(exhaust_results=False)
@@ -1436,6 +1446,8 @@ def outer_type_or_annotation(field):
14361446
if not isinstance(field.annotation, type):
14371447
raise AttributeError(f"could not extract outer type from field {field}")
14381448
return field.annotation
1449+
elif get_origin(field.annotation) == Literal:
1450+
return str
14391451
else:
14401452
return field.annotation.__args__[0]
14411453

@@ -2081,21 +2093,33 @@ def schema_for_type(
20812093
# find any values marked as indexed.
20822094
if is_container_type and not is_vector:
20832095
field_type = get_origin(typ)
2084-
embedded_cls = get_args(typ)
2085-
if not embedded_cls:
2086-
log.warning(
2087-
"Model %s defined an empty list or tuple field: %s", cls, name
2096+
if field_type == Literal:
2097+
path = f"{json_path}.{name}"
2098+
return cls.schema_for_type(
2099+
path,
2100+
name,
2101+
name_prefix,
2102+
str,
2103+
field_info,
2104+
parent_type=field_type,
2105+
)
2106+
else:
2107+
embedded_cls = get_args(typ)
2108+
if not embedded_cls:
2109+
log.warning(
2110+
"Model %s defined an empty list or tuple field: %s", cls, name
2111+
)
2112+
return ""
2113+
path = f"{json_path}.{name}[*]"
2114+
embedded_cls = embedded_cls[0]
2115+
return cls.schema_for_type(
2116+
path,
2117+
name,
2118+
name_prefix,
2119+
embedded_cls,
2120+
field_info,
2121+
parent_type=field_type,
20882122
)
2089-
return ""
2090-
embedded_cls = embedded_cls[0]
2091-
return cls.schema_for_type(
2092-
f"{json_path}.{name}[*]",
2093-
name,
2094-
name_prefix,
2095-
embedded_cls,
2096-
field_info,
2097-
parent_type=field_type,
2098-
)
20992123
elif field_is_model:
21002124
name_prefix = f"{name_prefix}_{name}" if name_prefix else name
21012125
sub_fields = []

pyproject.toml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "redis-om"
3-
version = "0.3.1"
3+
version = "0.3.2"
44
description = "Object mappings, and more, for Redis."
55
authors = ["Redis OSS <[email protected]>"]
66
maintainers = ["Redis OSS <[email protected]>"]
@@ -42,9 +42,9 @@ click = "^8.0.1"
4242
types-redis = ">=3.5.9,<5.0.0"
4343
python-ulid = "^1.0.3"
4444
typing-extensions = "^4.4.0"
45-
hiredis = "^2.2.3"
45+
hiredis = ">=2.2.3,<4.0.0"
4646
more-itertools = ">=8.14,<11.0"
47-
setuptools = {version = "^69.2.0", markers = "python_version >= '3.12'"}
47+
setuptools = {version = ">=70.0,<73.0", markers = "python_version >= '3.12'"}
4848

4949
[tool.poetry.dev-dependencies]
5050
mypy = "^1.9.0"
@@ -55,9 +55,9 @@ isort = "^5.9.3"
5555
flake8 = "^5.0.4"
5656
bandit = "^1.7.4"
5757
coverage = "^7.1"
58-
pytest-cov = "^4.0.0"
58+
pytest-cov = "^5.0.0"
5959
pytest-xdist = "^3.1.0"
60-
unasync = "^0.5.0"
60+
unasync = "^0.6.0"
6161
pytest-asyncio = "^0.23.5"
6262
email-validator = "^2.0.0"
6363
tox = "^4.14.1"

0 commit comments

Comments
 (0)