Skip to content

Commit c211db7

Browse files
authored
Merge pull request #46 from google/circular-dependency
Remove circular dependency between conditions and relationships
2 parents 48a500f + 0bc971e commit c211db7

2 files changed

Lines changed: 30 additions & 13 deletions

File tree

spanner_orm/condition.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,19 @@ def bind(self, model):
178178

179179
@property
180180
def conditions(self):
181+
"""Generate the child conditions based on the relationship constraints."""
181182
if not self.relation:
182183
raise error.SpannerError(
183184
'Condition must be bound before conditions is called')
184-
return self.relation.conditions + self._conditions
185+
relation_conditions = []
186+
for constraint in self.relation.constraints:
187+
# This is backward from what you might imagine because the condition will
188+
# be processed from the context of the destination model
189+
relation_conditions.append(
190+
ColumnsEqualCondition(constraint.destination_column,
191+
constraint.origin_class,
192+
constraint.origin_column))
193+
return relation_conditions + self._conditions
185194

186195
@property
187196
def destination(self):

spanner_orm/relationship.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,21 @@
1616

1717
from __future__ import annotations
1818

19-
from typing import Dict, List, Type, Union
19+
from typing import Any, Dict, List, Type, Union
2020

21-
from spanner_orm import condition
21+
import dataclasses
2222
from spanner_orm import error
2323
from spanner_orm import model
2424

2525

26+
@dataclasses.dataclass
27+
class RelationshipConstraint:
28+
destination_class: Type[Any]
29+
destination_column: str
30+
origin_class: Type[Any]
31+
origin_column: str
32+
33+
2634
class Relationship(object):
2735
"""Helps define a foreign key relationship between two models."""
2836

@@ -52,8 +60,8 @@ def __init__(self,
5260
self.origin = None
5361

5462
@property
55-
def conditions(self) -> List[condition.Condition]:
56-
assert self.origin, 'Origin must be set before conditions is called'
63+
def constraints(self) -> List[RelationshipConstraint]:
64+
assert self.origin, 'Origin must be set before constraints is called'
5765
return self._parse_constraints()
5866

5967
@property
@@ -66,9 +74,9 @@ def destination(self) -> Type[model.Model]:
6674
def single(self) -> bool:
6775
return self._single
6876

69-
def _parse_constraints(self) -> List[condition.Condition]:
77+
def _parse_constraints(self) -> List[RelationshipConstraint]:
7078
"""Validates the dictionary of constraints and turns it into Conditions."""
71-
conditions = []
79+
constraints = []
7280
for origin_column, destination_column in self._constraints.items():
7381
if origin_column not in self.origin.schema:
7482
raise error.SpannerError(
@@ -77,10 +85,10 @@ def _parse_constraints(self) -> List[condition.Condition]:
7785
if destination_column not in self.destination.schema:
7886
raise error.SpannerError(
7987
'Destination column must be present in destination model')
80-
# This is backward from what you might imagine because the condition will
81-
# be processed from the context of the destination model
82-
conditions.append(
83-
condition.ColumnsEqualCondition(destination_column, self.origin,
84-
origin_column))
8588

86-
return conditions
89+
# TODO(dbrandao): remove when pytype #234 is fixed
90+
constraints.append(
91+
RelationshipConstraint(self.destination, destination_column,
92+
self.origin, origin_column)) # type: ignore
93+
94+
return constraints

0 commit comments

Comments
 (0)