-
-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support to secondary tables relationships #218
base: main
Are you sure you want to change the base?
Changes from 19 commits
de06188
0cd732d
401cd65
6f644e3
ca9bc1c
eb852ce
5770379
be77996
fb6a580
0fb61bb
03a5438
a575650
beaa3f9
8a65328
9d76061
91c24c5
1cd8df4
e96f179
4b6516b
9b079d4
4baa7ae
33d7758
2a53474
d04af46
3f7f13d
ff3e419
6752231
0cd68d2
0745c64
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -11,6 +11,7 @@ | |||||||||||||||||||||
Tuple, | ||||||||||||||||||||||
Union, | ||||||||||||||||||||||
) | ||||||||||||||||||||||
from strawberry_sqlalchemy_mapper.exc import InvalidLocalRemotePairs | ||||||||||||||||||||||
|
||||||||||||||||||||||
from sqlalchemy import select, tuple_ | ||||||||||||||||||||||
from sqlalchemy.engine.base import Connection | ||||||||||||||||||||||
|
@@ -45,12 +46,16 @@ def __init__( | |||||||||||||||||||||
"One of bind or async_bind_factory must be set for loader to function properly." | ||||||||||||||||||||||
) | ||||||||||||||||||||||
|
||||||||||||||||||||||
async def _scalars_all(self, *args, **kwargs): | ||||||||||||||||||||||
async def _scalars_all(self, *args, disabled_optimization_to_secondary_tables=False, **kwargs): | ||||||||||||||||||||||
if self._async_bind_factory: | ||||||||||||||||||||||
async with self._async_bind_factory() as bind: | ||||||||||||||||||||||
if disabled_optimization_to_secondary_tables is True: | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated! Thank you There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated! |
||||||||||||||||||||||
return (await bind.execute(*args, **kwargs)).all() | ||||||||||||||||||||||
return (await bind.scalars(*args, **kwargs)).all() | ||||||||||||||||||||||
else: | ||||||||||||||||||||||
assert self._bind is not None | ||||||||||||||||||||||
if disabled_optimization_to_secondary_tables is True: | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated! |
||||||||||||||||||||||
return self._bind.execute(*args, **kwargs).all() | ||||||||||||||||||||||
return self._bind.scalars(*args, **kwargs).all() | ||||||||||||||||||||||
|
||||||||||||||||||||||
def loader_for(self, relationship: RelationshipProperty) -> DataLoader: | ||||||||||||||||||||||
|
@@ -63,14 +68,63 @@ def loader_for(self, relationship: RelationshipProperty) -> DataLoader: | |||||||||||||||||||||
related_model = relationship.entity.entity | ||||||||||||||||||||||
|
||||||||||||||||||||||
async def load_fn(keys: List[Tuple]) -> List[Any]: | ||||||||||||||||||||||
query = select(related_model).filter( | ||||||||||||||||||||||
tuple_( | ||||||||||||||||||||||
*[remote for _, remote in relationship.local_remote_pairs or []] | ||||||||||||||||||||||
).in_(keys) | ||||||||||||||||||||||
) | ||||||||||||||||||||||
if relationship.secondary is None: | ||||||||||||||||||||||
sourcery-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
query = select(related_model).filter( | ||||||||||||||||||||||
tuple_( | ||||||||||||||||||||||
*[remote for _, remote in relationship.local_remote_pairs or []] | ||||||||||||||||||||||
).in_(keys) | ||||||||||||||||||||||
) | ||||||||||||||||||||||
else: | ||||||||||||||||||||||
# Use another query when relationship uses a secondary table | ||||||||||||||||||||||
self_model = relationship.parent.entity | ||||||||||||||||||||||
|
||||||||||||||||||||||
if not relationship.local_remote_pairs: | ||||||||||||||||||||||
raise InvalidLocalRemotePairs( | ||||||||||||||||||||||
f"{related_model.__name__} -- {self_model.__name__}") | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. polish: for Also, we are probably missing a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry about that, I see now that pre-commit dont run due to some updates that dont work with dev container python version (3.8). |
||||||||||||||||||||||
|
||||||||||||||||||||||
self_model_key_label = str( | ||||||||||||||||||||||
relationship.local_remote_pairs[0][1].key) | ||||||||||||||||||||||
related_model_key_label = str( | ||||||||||||||||||||||
relationship.local_remote_pairs[1][1].key) | ||||||||||||||||||||||
|
||||||||||||||||||||||
self_model_key = str( | ||||||||||||||||||||||
relationship.local_remote_pairs[0][0].key) | ||||||||||||||||||||||
related_model_key = str( | ||||||||||||||||||||||
relationship.local_remote_pairs[1][0].key) | ||||||||||||||||||||||
|
||||||||||||||||||||||
remote_to_use = relationship.local_remote_pairs[0][1] | ||||||||||||||||||||||
query_keys = tuple([item[0] for item in keys]) | ||||||||||||||||||||||
|
||||||||||||||||||||||
# This query returns rows in this format -> (self_model.key, related_model) | ||||||||||||||||||||||
query = ( | ||||||||||||||||||||||
select( | ||||||||||||||||||||||
getattr(self_model, self_model_key).label( | ||||||||||||||||||||||
self_model_key_label), | ||||||||||||||||||||||
related_model | ||||||||||||||||||||||
) | ||||||||||||||||||||||
.join( | ||||||||||||||||||||||
sourcery-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
relationship.secondary, | ||||||||||||||||||||||
getattr(relationship.secondary.c, | ||||||||||||||||||||||
related_model_key_label) == getattr(related_model, related_model_key) | ||||||||||||||||||||||
) | ||||||||||||||||||||||
.join( | ||||||||||||||||||||||
self_model, | ||||||||||||||||||||||
getattr(relationship.secondary.c, | ||||||||||||||||||||||
self_model_key_label) == getattr(self_model, self_model_key) | ||||||||||||||||||||||
) | ||||||||||||||||||||||
.filter( | ||||||||||||||||||||||
remote_to_use.in_(query_keys) | ||||||||||||||||||||||
) | ||||||||||||||||||||||
) | ||||||||||||||||||||||
|
||||||||||||||||||||||
if relationship.order_by: | ||||||||||||||||||||||
query = query.order_by(*relationship.order_by) | ||||||||||||||||||||||
rows = await self._scalars_all(query) | ||||||||||||||||||||||
|
||||||||||||||||||||||
if relationship.secondary is not None: | ||||||||||||||||||||||
# We need to retrieve values from both the self_model and related_model. To achieve this, we must disable the default SQLAlchemy optimization that returns only related_model values. This is necessary because we use the keys variable to match both related_model and self_model. | ||||||||||||||||||||||
rows = await self._scalars_all(query, disabled_optimization_to_secondary_tables=True) | ||||||||||||||||||||||
else: | ||||||||||||||||||||||
rows = await self._scalars_all(query) | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! Updated! |
||||||||||||||||||||||
|
||||||||||||||||||||||
def group_by_remote_key(row: Any) -> Tuple: | ||||||||||||||||||||||
return tuple( | ||||||||||||||||||||||
|
@@ -82,8 +136,13 @@ def group_by_remote_key(row: Any) -> Tuple: | |||||||||||||||||||||
) | ||||||||||||||||||||||
|
||||||||||||||||||||||
grouped_keys: Mapping[Tuple, List[Any]] = defaultdict(list) | ||||||||||||||||||||||
for row in rows: | ||||||||||||||||||||||
grouped_keys[group_by_remote_key(row)].append(row) | ||||||||||||||||||||||
if relationship.secondary is None: | ||||||||||||||||||||||
for row in rows: | ||||||||||||||||||||||
grouped_keys[group_by_remote_key(row)].append(row) | ||||||||||||||||||||||
else: | ||||||||||||||||||||||
for row in rows: | ||||||||||||||||||||||
grouped_keys[(row[0],)].append(row[1]) | ||||||||||||||||||||||
|
||||||||||||||||||||||
if relationship.uselist: | ||||||||||||||||||||||
return [grouped_keys[key] for key in keys] | ||||||||||||||||||||||
else: | ||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -82,6 +82,7 @@ | |||||||||||||||||
from strawberry_sqlalchemy_mapper.exc import ( | ||||||||||||||||||
HybridPropertyNotAnnotated, | ||||||||||||||||||
InterfaceModelNotPolymorphic, | ||||||||||||||||||
InvalidLocalRemotePairs, | ||||||||||||||||||
UnsupportedAssociationProxyTarget, | ||||||||||||||||||
UnsupportedColumnType, | ||||||||||||||||||
UnsupportedDescriptorType, | ||||||||||||||||||
|
@@ -154,7 +155,8 @@ def from_type(cls, type_: type, *, strict: Literal[True]) -> Self: ... | |||||||||||||||||
|
||||||||||||||||||
@overload | ||||||||||||||||||
@classmethod | ||||||||||||||||||
def from_type(cls, type_: type, *, strict: bool = False) -> Optional[Self]: ... | ||||||||||||||||||
def from_type(cls, type_: type, *, | ||||||||||||||||||
strict: bool = False) -> Optional[Self]: ... | ||||||||||||||||||
|
||||||||||||||||||
@classmethod | ||||||||||||||||||
def from_type( | ||||||||||||||||||
|
@@ -165,7 +167,8 @@ def from_type( | |||||||||||||||||
) -> Optional[Self]: | ||||||||||||||||||
definition = getattr(type_, cls.TYPE_KEY_NAME, None) | ||||||||||||||||||
if strict and definition is None: | ||||||||||||||||||
raise TypeError(f"{type_!r} does not have a StrawberrySQLAlchemyType in it") | ||||||||||||||||||
raise TypeError( | ||||||||||||||||||
f"{type_!r} does not have a StrawberrySQLAlchemyType in it") | ||||||||||||||||||
return definition | ||||||||||||||||||
|
||||||||||||||||||
|
||||||||||||||||||
|
@@ -228,11 +231,12 @@ class StrawberrySQLAlchemyMapper(Generic[BaseModelType]): | |||||||||||||||||
|
||||||||||||||||||
def __init__( | ||||||||||||||||||
self, | ||||||||||||||||||
model_to_type_name: Optional[Callable[[Type[BaseModelType]], str]] = None, | ||||||||||||||||||
model_to_interface_name: Optional[Callable[[Type[BaseModelType]], str]] = None, | ||||||||||||||||||
extra_sqlalchemy_type_to_strawberry_type_map: Optional[ | ||||||||||||||||||
Mapping[Type[TypeEngine], Type[Any]] | ||||||||||||||||||
] = None, | ||||||||||||||||||
model_to_type_name: Optional[Callable[[ | ||||||||||||||||||
Type[BaseModelType]], str]] = None, | ||||||||||||||||||
model_to_interface_name: Optional[Callable[[ | ||||||||||||||||||
Type[BaseModelType]], str]] = None, | ||||||||||||||||||
extra_sqlalchemy_type_to_strawberry_type_map: Optional[Mapping[Type[TypeEngine], Type[Any]] | ||||||||||||||||||
] = None, | ||||||||||||||||||
) -> None: | ||||||||||||||||||
if model_to_type_name is None: | ||||||||||||||||||
model_to_type_name = self._default_model_to_type_name | ||||||||||||||||||
|
@@ -295,7 +299,8 @@ def _edge_type_for(self, type_name: str) -> Type[Any]: | |||||||||||||||||
""" | ||||||||||||||||||
edge_name = f"{type_name}Edge" | ||||||||||||||||||
if edge_name not in self.edge_types: | ||||||||||||||||||
lazy_type = StrawberrySQLAlchemyLazy(type_name=type_name, mapper=self) | ||||||||||||||||||
lazy_type = StrawberrySQLAlchemyLazy( | ||||||||||||||||||
type_name=type_name, mapper=self) | ||||||||||||||||||
self.edge_types[edge_name] = edge_type = strawberry.type( | ||||||||||||||||||
dataclasses.make_dataclass( | ||||||||||||||||||
edge_name, | ||||||||||||||||||
|
@@ -314,14 +319,15 @@ def _connection_type_for(self, type_name: str) -> Type[Any]: | |||||||||||||||||
connection_name = f"{type_name}Connection" | ||||||||||||||||||
if connection_name not in self.connection_types: | ||||||||||||||||||
edge_type = self._edge_type_for(type_name) | ||||||||||||||||||
lazy_type = StrawberrySQLAlchemyLazy(type_name=type_name, mapper=self) | ||||||||||||||||||
lazy_type = StrawberrySQLAlchemyLazy( | ||||||||||||||||||
type_name=type_name, mapper=self) | ||||||||||||||||||
self.connection_types[connection_name] = connection_type = strawberry.type( | ||||||||||||||||||
dataclasses.make_dataclass( | ||||||||||||||||||
connection_name, | ||||||||||||||||||
[ | ||||||||||||||||||
("edges", List[edge_type]), # type: ignore[valid-type] | ||||||||||||||||||
], | ||||||||||||||||||
bases=(relay.ListConnection[lazy_type],), # type: ignore[valid-type] | ||||||||||||||||||
bases=(relay.ListConnection[lazy_type],), # type: ignore[valid-type] | ||||||||||||||||||
) | ||||||||||||||||||
) | ||||||||||||||||||
setattr(connection_type, _GENERATED_FIELD_KEYS_KEY, ["edges"]) | ||||||||||||||||||
|
@@ -387,7 +393,7 @@ def _convert_relationship_to_strawberry_type( | |||||||||||||||||
if relationship.uselist: | ||||||||||||||||||
# Use list if excluding relay pagination | ||||||||||||||||||
if use_list: | ||||||||||||||||||
return List[ForwardRef(type_name)] # type: ignore | ||||||||||||||||||
return List[ForwardRef(type_name)] # type: ignore | ||||||||||||||||||
|
||||||||||||||||||
return self._connection_type_for(type_name) | ||||||||||||||||||
else: | ||||||||||||||||||
|
@@ -451,7 +457,8 @@ def _get_association_proxy_annotation( | |||||||||||||||||
strawberry_type.__forward_arg__ | ||||||||||||||||||
) | ||||||||||||||||||
else: | ||||||||||||||||||
strawberry_type = self._connection_type_for(strawberry_type.__name__) | ||||||||||||||||||
strawberry_type = self._connection_type_for( | ||||||||||||||||||
strawberry_type.__name__) | ||||||||||||||||||
return strawberry_type | ||||||||||||||||||
|
||||||||||||||||||
def make_connection_wrapper_resolver( | ||||||||||||||||||
|
@@ -500,13 +507,29 @@ async def resolve(self, info: Info): | |||||||||||||||||
if relationship.key not in instance_state.unloaded: | ||||||||||||||||||
related_objects = getattr(self, relationship.key) | ||||||||||||||||||
else: | ||||||||||||||||||
relationship_key = tuple( | ||||||||||||||||||
[ | ||||||||||||||||||
getattr(self, local.key) | ||||||||||||||||||
for local, _ in relationship.local_remote_pairs or [] | ||||||||||||||||||
if local.key | ||||||||||||||||||
] | ||||||||||||||||||
) | ||||||||||||||||||
if relationship.secondary is None: | ||||||||||||||||||
relationship_key = tuple( | ||||||||||||||||||
[ | ||||||||||||||||||
getattr(self, local.key) | ||||||||||||||||||
for local, _ in relationship.local_remote_pairs or [] | ||||||||||||||||||
if local.key | ||||||||||||||||||
] | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. praise: you can pass the iterator to the tuple directly, no need to create a list for that
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated! |
||||||||||||||||||
) | ||||||||||||||||||
else: | ||||||||||||||||||
# If has a secondary table, gets only the first ID as additional IDs require a separate query | ||||||||||||||||||
if not relationship.local_remote_pairs: | ||||||||||||||||||
raise InvalidLocalRemotePairs( | ||||||||||||||||||
f"{relationship.entity.entity.__name__} -- {relationship.parent.entity.__name__}") | ||||||||||||||||||
|
||||||||||||||||||
local_remote_pairs_secondary_table_local = relationship.local_remote_pairs[ | ||||||||||||||||||
0][0] | ||||||||||||||||||
relationship_key = tuple( | ||||||||||||||||||
[ | ||||||||||||||||||
getattr( | ||||||||||||||||||
self, str(local_remote_pairs_secondary_table_local.key)), | ||||||||||||||||||
] | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: ditto There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated! |
||||||||||||||||||
) | ||||||||||||||||||
|
||||||||||||||||||
if any(item is None for item in relationship_key): | ||||||||||||||||||
if relationship.uselist: | ||||||||||||||||||
return [] | ||||||||||||||||||
|
@@ -536,7 +559,8 @@ def connection_resolver_for( | |||||||||||||||||
if relationship.uselist and not use_list: | ||||||||||||||||||
return self.make_connection_wrapper_resolver( | ||||||||||||||||||
relationship_resolver, | ||||||||||||||||||
self.model_to_type_or_interface_name(relationship.entity.entity), # type: ignore[arg-type] | ||||||||||||||||||
self.model_to_type_or_interface_name( | ||||||||||||||||||
relationship.entity.entity), # type: ignore[arg-type] | ||||||||||||||||||
) | ||||||||||||||||||
else: | ||||||||||||||||||
return relationship_resolver | ||||||||||||||||||
|
@@ -554,13 +578,15 @@ def association_proxy_resolver_for( | |||||||||||||||||
Return an async field resolver for the given association proxy. | ||||||||||||||||||
""" | ||||||||||||||||||
in_between_relationship = mapper.relationships[descriptor.target_collection] | ||||||||||||||||||
in_between_resolver = self.relationship_resolver_for(in_between_relationship) | ||||||||||||||||||
in_between_resolver = self.relationship_resolver_for( | ||||||||||||||||||
in_between_relationship) | ||||||||||||||||||
in_between_mapper: Mapper = mapper.relationships[ # type: ignore[assignment] | ||||||||||||||||||
descriptor.target_collection | ||||||||||||||||||
].entity | ||||||||||||||||||
assert descriptor.value_attr in in_between_mapper.relationships | ||||||||||||||||||
end_relationship = in_between_mapper.relationships[descriptor.value_attr] | ||||||||||||||||||
end_relationship_resolver = self.relationship_resolver_for(end_relationship) | ||||||||||||||||||
end_relationship_resolver = self.relationship_resolver_for( | ||||||||||||||||||
end_relationship) | ||||||||||||||||||
end_type_name = self.model_to_type_or_interface_name( | ||||||||||||||||||
end_relationship.entity.entity # type: ignore[arg-type] | ||||||||||||||||||
) | ||||||||||||||||||
|
@@ -587,7 +613,8 @@ async def resolve(self, info: Info): | |||||||||||||||||
if outputs and isinstance(outputs[0], list): | ||||||||||||||||||
outputs = list(chain.from_iterable(outputs)) | ||||||||||||||||||
else: | ||||||||||||||||||
outputs = [output for output in outputs if output is not None] | ||||||||||||||||||
outputs = [ | ||||||||||||||||||
output for output in outputs if output is not None] | ||||||||||||||||||
else: | ||||||||||||||||||
outputs = await end_relationship_resolver(in_between_objects, info) | ||||||||||||||||||
if not isinstance(outputs, collections.abc.Iterable): | ||||||||||||||||||
|
@@ -683,7 +710,8 @@ def convert(type_: Any) -> Any: | |||||||||||||||||
setattr(type_, key, field(resolver=val)) | ||||||||||||||||||
generated_field_keys.append(key) | ||||||||||||||||||
|
||||||||||||||||||
self._handle_columns(mapper, type_, excluded_keys, generated_field_keys) | ||||||||||||||||||
self._handle_columns( | ||||||||||||||||||
mapper, type_, excluded_keys, generated_field_keys) | ||||||||||||||||||
relationship: RelationshipProperty | ||||||||||||||||||
for key, relationship in mapper.relationships.items(): | ||||||||||||||||||
if ( | ||||||||||||||||||
|
@@ -805,7 +833,7 @@ def convert(type_: Any) -> Any: | |||||||||||||||||
setattr( | ||||||||||||||||||
type_, | ||||||||||||||||||
attr, | ||||||||||||||||||
types.MethodType(func, type_), # type: ignore[arg-type] | ||||||||||||||||||
types.MethodType(func, type_), # type: ignore[arg-type] | ||||||||||||||||||
) | ||||||||||||||||||
|
||||||||||||||||||
# Adjust types that inherit from other types/interfaces that implement Node | ||||||||||||||||||
|
@@ -818,7 +846,8 @@ def convert(type_: Any) -> Any: | |||||||||||||||||
setattr( | ||||||||||||||||||
type_, | ||||||||||||||||||
attr, | ||||||||||||||||||
types.MethodType(cast(classmethod, meth).__func__, type_), | ||||||||||||||||||
types.MethodType( | ||||||||||||||||||
cast(classmethod, meth).__func__, type_), | ||||||||||||||||||
) | ||||||||||||||||||
|
||||||||||||||||||
# need to make fields that are already in the type | ||||||||||||||||||
|
@@ -846,7 +875,8 @@ def convert(type_: Any) -> Any: | |||||||||||||||||
model=model, | ||||||||||||||||||
), | ||||||||||||||||||
) | ||||||||||||||||||
setattr(mapped_type, _GENERATED_FIELD_KEYS_KEY, generated_field_keys) | ||||||||||||||||||
setattr(mapped_type, _GENERATED_FIELD_KEYS_KEY, | ||||||||||||||||||
generated_field_keys) | ||||||||||||||||||
setattr(mapped_type, _ORIGINAL_TYPE_KEY, type_) | ||||||||||||||||||
return mapped_type | ||||||||||||||||||
|
||||||||||||||||||
|
@@ -886,14 +916,16 @@ def _fix_annotation_namespaces(self) -> None: | |||||||||||||||||
self.edge_types.values(), | ||||||||||||||||||
self.connection_types.values(), | ||||||||||||||||||
): | ||||||||||||||||||
strawberry_definition = get_object_definition(mapped_type, strict=True) | ||||||||||||||||||
strawberry_definition = get_object_definition( | ||||||||||||||||||
mapped_type, strict=True) | ||||||||||||||||||
for f in strawberry_definition.fields: | ||||||||||||||||||
if f.name in getattr(mapped_type, _GENERATED_FIELD_KEYS_KEY): | ||||||||||||||||||
namespace = {} | ||||||||||||||||||
if hasattr(mapped_type, _ORIGINAL_TYPE_KEY): | ||||||||||||||||||
namespace.update( | ||||||||||||||||||
sys.modules[ | ||||||||||||||||||
getattr(mapped_type, _ORIGINAL_TYPE_KEY).__module__ | ||||||||||||||||||
getattr(mapped_type, | ||||||||||||||||||
_ORIGINAL_TYPE_KEY).__module__ | ||||||||||||||||||
].__dict__ | ||||||||||||||||||
) | ||||||||||||||||||
namespace.update(self.mapped_types) | ||||||||||||||||||
|
@@ -924,7 +956,8 @@ def _map_unmapped_relationships(self) -> None: | |||||||||||||||||
if type_name not in self.mapped_interfaces: | ||||||||||||||||||
unmapped_interface_models.add(model) | ||||||||||||||||||
for model in unmapped_models: | ||||||||||||||||||
self.type(model)(type(self.model_to_type_name(model), (object,), {})) | ||||||||||||||||||
self.type(model)( | ||||||||||||||||||
type(self.model_to_type_name(model), (object,), {})) | ||||||||||||||||||
for model in unmapped_interface_models: | ||||||||||||||||||
self.interface(model)( | ||||||||||||||||||
type(self.model_to_interface_name(model), (object,), {}) | ||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: maybe call this
enable_
and haveTrue
as the default?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont want to do this because it removes optimizations that we only need to remove when we need to pick up secondary tables values, so if the default is True we will lose peformance in queries that dont need it.
But I agree that this var name aren't good enought, so I will change the name to
query_secondary_tables
and refactor the function.