Skip to content

Commit 5007515

Browse files
authored
Merge branch 'main' into fix/647
2 parents 90e95fb + d0e3a68 commit 5007515

File tree

5 files changed

+37
-17
lines changed

5 files changed

+37
-17
lines changed

.github/workflows/spellcheck.yml

Lines changed: 1 addition & 1 deletion
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.40.0
11+
uses: rojopolis/spellcheck-github-actions@0.44.0
1212
with:
1313
config_path: .github/spellcheck-settings.yml
1414
task_name: Markdown

aredis_om/model/encoders.py

Lines changed: 1 addition & 1 deletion
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) # type: ignore[call-overload]
93+
return dataclasses.asdict(obj) # type: ignore
9494
if isinstance(obj, Enum):
9595
return obj.value
9696
if isinstance(obj, PurePath):

aredis_om/model/model.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def score_field(self) -> str:
309309
class ExpressionProxy:
310310
def __init__(self, field: ModelField, parents: List[Tuple[str, "RedisModel"]]):
311311
self.field = field
312-
self.parents = parents
312+
self.parents = parents.copy() # Ensure a copy is stored
313313

314314
def __eq__(self, other: Any) -> Expression: # type: ignore[override]
315315
return Expression(
@@ -387,13 +387,14 @@ def __getattr__(self, item):
387387
attr = getattr(embedded_cls, item)
388388
else:
389389
attr = getattr(outer_type, item)
390+
390391
if isinstance(attr, self.__class__):
392+
# Clone the parents to ensure isolation
393+
new_parents = self.parents.copy()
391394
new_parent = (self.field.alias, outer_type)
392-
if new_parent not in attr.parents:
393-
attr.parents.append(new_parent)
394-
new_parents = list(set(self.parents) - set(attr.parents))
395-
if new_parents:
396-
attr.parents = new_parents + attr.parents
395+
if new_parent not in new_parents:
396+
new_parents.append(new_parent)
397+
attr.parents = new_parents
397398
return attr
398399

399400

@@ -632,10 +633,11 @@ def resolve_value(
632633
value: Any,
633634
parents: List[Tuple[str, "RedisModel"]],
634635
) -> str:
636+
# The 'field_name' should already include the correct prefix
637+
result = ""
635638
if parents:
636639
prefix = "_".join([p[0] for p in parents])
637640
field_name = f"{prefix}_{field_name}"
638-
result = ""
639641
if field_type is RediSearchFieldTypes.TEXT:
640642
result = f"@{field_name}_fts:"
641643
if op is Operators.EQ:
@@ -792,8 +794,6 @@ def resolve_redisearch_query(cls, expression: ExpressionOrNegated) -> str:
792794

793795
if expression.op is Operators.ALL:
794796
if encompassing_expression_is_negated:
795-
# TODO: Is there a use case for this, perhaps for dynamic
796-
# scoring purposes with full-text search?
797797
raise QueryNotSupportedError(
798798
"You cannot negate a query for all results."
799799
)
@@ -827,6 +827,11 @@ def resolve_redisearch_query(cls, expression: ExpressionOrNegated) -> str:
827827
f"or an expression enclosed in parentheses. Docs: {ERRORS_URL}#E7"
828828
)
829829

830+
if isinstance(expression.left, ModelField) and expression.parents:
831+
# Build field_name using the specific parents for this expression
832+
prefix = "_".join([p[0] for p in expression.parents])
833+
field_name = f"{prefix}_{field_name}"
834+
830835
right = expression.right
831836

832837
if isinstance(right, Expression) or isinstance(right, NegatedExpression):
@@ -842,8 +847,6 @@ def resolve_redisearch_query(cls, expression: ExpressionOrNegated) -> str:
842847

843848
if isinstance(right, NegatedExpression):
844849
result += "-"
845-
# We're handling the RediSearch operator in this call ("-"), so resolve the
846-
# inner expression instead of the NegatedExpression.
847850
right = right.expression
848851

849852
result += f"({cls.resolve_redisearch_query(right)})"
@@ -1432,7 +1435,8 @@ def outer_type_or_annotation(field):
14321435

14331436
class RedisModel(BaseModel, abc.ABC, metaclass=ModelMeta):
14341437
pk: Optional[str] = Field(default=None, primary_key=True)
1435-
ConfigDict: ClassVar
1438+
if PYDANTIC_V2:
1439+
ConfigDict: ClassVar
14361440

14371441
Meta = DefaultMeta
14381442

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "redis-om"
3-
version = "0.3.2"
3+
version = "0.3.3"
44
description = "Object mappings, and more, for Redis."
55
authors = ["Redis OSS <[email protected]>"]
66
maintainers = ["Redis OSS <[email protected]>"]
@@ -44,7 +44,7 @@ python-ulid = "^1.0.3"
4444
typing-extensions = "^4.4.0"
4545
hiredis = ">=2.2.3,<4.0.0"
4646
more-itertools = ">=8.14,<11.0"
47-
setuptools = {version = ">=70.0,<73.0", markers = "python_version >= '3.12'"}
47+
setuptools = {version = ">=70.0,<76.0", markers = "python_version >= '3.12'"}
4848

4949
[tool.poetry.dev-dependencies]
5050
mypy = "^1.9.0"
@@ -58,7 +58,7 @@ coverage = "^7.1"
5858
pytest-cov = "^5.0.0"
5959
pytest-xdist = "^3.1.0"
6060
unasync = "^0.6.0"
61-
pytest-asyncio = "^0.23.5"
61+
pytest-asyncio = "^0.24.0"
6262
email-validator = "^2.0.0"
6363
tox = "^4.14.1"
6464
tox-pyenv = "^1.1.0"

tests/test_json_model.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,3 +1157,19 @@ class TestLiterals(JsonModel):
11571157
await item.save()
11581158
rematerialized = await TestLiterals.find(TestLiterals.flavor == "pumpkin").first()
11591159
assert rematerialized.pk == item.pk
1160+
1161+
1162+
@py_test_mark_asyncio
1163+
async def test_merged_model_error():
1164+
class Player(EmbeddedJsonModel):
1165+
username: str = Field(index=True)
1166+
1167+
class Game(JsonModel):
1168+
player1: Optional[Player]
1169+
player2: Optional[Player]
1170+
1171+
q = Game.find(
1172+
(Game.player1.username == "username") | (Game.player2.username == "username")
1173+
)
1174+
print(q.query)
1175+
assert q.query == "(@player1_username:{username})| (@player2_username:{username})"

0 commit comments

Comments
 (0)