Skip to content

Commit c984d77

Browse files
zzzeekGerrit Code Review
authored andcommitted
Merge "use metadata.reflect() for DeferredReflection" into main
2 parents 8fe6a3f + 6cc063f commit c984d77

1 file changed

Lines changed: 55 additions & 32 deletions

File tree

lib/sqlalchemy/ext/declarative/extensions.py

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
"""Public API functions and helpers for declarative."""
1111
from __future__ import annotations
1212

13+
import collections
1314
from typing import Callable
1415
from typing import TYPE_CHECKING
1516

16-
from ... import inspection
1717
from ...orm import exc as orm_exc
1818
from ...orm import relationships
1919
from ...orm.base import _mapper_or_none
@@ -24,7 +24,6 @@
2424
from ...util import OrderedDict
2525

2626
if TYPE_CHECKING:
27-
from ...engine.reflection import Inspector
2827
from ...sql.schema import MetaData
2928

3029

@@ -385,12 +384,38 @@ def prepare(cls, engine):
385384

386385
to_map = _DeferredMapperConfig.classes_for_base(cls)
387386

388-
with inspection.inspect(engine)._inspection_context() as insp:
387+
metadata_to_table = collections.defaultdict(set)
388+
389+
# first collect the primary __table__ for each class into a
390+
# collection of metadata/schemaname -> table names
391+
for thingy in to_map:
392+
393+
if thingy.local_table is not None:
394+
metadata_to_table[
395+
(thingy.local_table.metadata, thingy.local_table.schema)
396+
].add(thingy.local_table.name)
397+
398+
# then reflect all those tables into their metadatas
399+
with engine.connect() as conn:
400+
for (metadata, schema), table_names in metadata_to_table.items():
401+
metadata.reflect(
402+
conn,
403+
only=table_names,
404+
schema=schema,
405+
extend_existing=True,
406+
autoload_replace=False,
407+
)
408+
409+
metadata_to_table.clear()
410+
411+
# .map() each class, then go through relationships and look
412+
# for secondary
389413
for thingy in to_map:
390-
cls._sa_decl_prepare(thingy.local_table, insp)
391414
thingy.map()
415+
392416
mapper = thingy.cls.__mapper__
393417
metadata = mapper.class_.metadata
418+
394419
for rel in mapper._props.values():
395420

396421
if (
@@ -401,41 +426,50 @@ def prepare(cls, engine):
401426
secondary_arg = rel._init_args.secondary
402427

403428
if isinstance(secondary_arg.argument, Table):
404-
cls._reflect_table(secondary_arg.argument, insp)
429+
secondary_table = secondary_arg.argument
430+
metadata_to_table[
431+
(
432+
secondary_table.metadata,
433+
secondary_table.schema,
434+
)
435+
].add(secondary_table.name)
405436
elif isinstance(secondary_arg.argument, str):
406-
407437
_, resolve_arg = _resolver(rel.parent.class_, rel)
408438

409439
resolver = resolve_arg(
410440
secondary_arg.argument, True
411441
)
442+
metadata_to_table[
443+
(metadata, thingy.local_table.schema)
444+
].add(secondary_arg.argument)
445+
412446
resolver._resolvers += (
413-
cls._sa_deferred_table_resolver(
414-
insp, metadata
415-
),
447+
cls._sa_deferred_table_resolver(metadata),
416448
)
417449

418450
secondary_arg.argument = resolver()
419451

452+
for (metadata, schema), table_names in metadata_to_table.items():
453+
metadata.reflect(
454+
conn,
455+
only=table_names,
456+
schema=schema,
457+
extend_existing=True,
458+
autoload_replace=False,
459+
)
460+
420461
@classmethod
421462
def _sa_deferred_table_resolver(
422-
cls, inspector: Inspector, metadata: MetaData
463+
cls, metadata: MetaData
423464
) -> Callable[[str], Table]:
424465
def _resolve(key: str) -> Table:
425-
t1 = Table(key, metadata)
426-
cls._reflect_table(t1, inspector)
427-
return t1
466+
# reflection has already occurred so this Table would have
467+
# its contents already
468+
return Table(key, metadata)
428469

429470
return _resolve
430471

431-
@classmethod
432-
def _sa_decl_prepare(cls, local_table, inspector):
433-
# autoload Table, which is already
434-
# present in the metadata. This
435-
# will fill in db-loaded columns
436-
# into the existing Table object.
437-
if local_table is not None:
438-
cls._reflect_table(local_table, inspector)
472+
_sa_decl_prepare = True
439473

440474
@classmethod
441475
def _sa_raise_deferred_config(cls):
@@ -446,14 +480,3 @@ def _sa_raise_deferred_config(cls):
446480
"method is called on the class hierarchy."
447481
% orm_exc._safe_cls_name(cls),
448482
)
449-
450-
@classmethod
451-
def _reflect_table(cls, table, inspector):
452-
Table(
453-
table.name,
454-
table.metadata,
455-
extend_existing=True,
456-
autoload_replace=False,
457-
autoload_with=inspector,
458-
schema=table.schema,
459-
)

0 commit comments

Comments
 (0)