You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					979 lines
				
				30 KiB
			
		
		
			
		
	
	
					979 lines
				
				30 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								# orm/interfaces.py
							 | 
						||
| 
								 | 
							
								# Copyright (C) 2005-2022 the SQLAlchemy authors and contributors
							 | 
						||
| 
								 | 
							
								# <see AUTHORS file>
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# This module is part of SQLAlchemy and is released under
							 | 
						||
| 
								 | 
							
								# the MIT License: https://www.opensource.org/licenses/mit-license.php
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Contains various base classes used throughout the ORM.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Defines some key base classes prominent within the internals.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This module and the classes within are mostly private, though some attributes
							 | 
						||
| 
								 | 
							
								are exposed when inspecting mappings.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from __future__ import absolute_import
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import collections
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from . import exc as orm_exc
							 | 
						||
| 
								 | 
							
								from . import path_registry
							 | 
						||
| 
								 | 
							
								from .base import _MappedAttribute  # noqa
							 | 
						||
| 
								 | 
							
								from .base import EXT_CONTINUE
							 | 
						||
| 
								 | 
							
								from .base import EXT_SKIP
							 | 
						||
| 
								 | 
							
								from .base import EXT_STOP
							 | 
						||
| 
								 | 
							
								from .base import InspectionAttr  # noqa
							 | 
						||
| 
								 | 
							
								from .base import InspectionAttrInfo  # noqa
							 | 
						||
| 
								 | 
							
								from .base import MANYTOMANY
							 | 
						||
| 
								 | 
							
								from .base import MANYTOONE
							 | 
						||
| 
								 | 
							
								from .base import NOT_EXTENSION
							 | 
						||
| 
								 | 
							
								from .base import ONETOMANY
							 | 
						||
| 
								 | 
							
								from .. import inspect
							 | 
						||
| 
								 | 
							
								from .. import inspection
							 | 
						||
| 
								 | 
							
								from .. import util
							 | 
						||
| 
								 | 
							
								from ..sql import operators
							 | 
						||
| 
								 | 
							
								from ..sql import roles
							 | 
						||
| 
								 | 
							
								from ..sql import visitors
							 | 
						||
| 
								 | 
							
								from ..sql.base import ExecutableOption
							 | 
						||
| 
								 | 
							
								from ..sql.traversals import HasCacheKey
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								__all__ = (
							 | 
						||
| 
								 | 
							
								    "EXT_CONTINUE",
							 | 
						||
| 
								 | 
							
								    "EXT_STOP",
							 | 
						||
| 
								 | 
							
								    "EXT_SKIP",
							 | 
						||
| 
								 | 
							
								    "ONETOMANY",
							 | 
						||
| 
								 | 
							
								    "MANYTOMANY",
							 | 
						||
| 
								 | 
							
								    "MANYTOONE",
							 | 
						||
| 
								 | 
							
								    "NOT_EXTENSION",
							 | 
						||
| 
								 | 
							
								    "LoaderStrategy",
							 | 
						||
| 
								 | 
							
								    "MapperOption",
							 | 
						||
| 
								 | 
							
								    "LoaderOption",
							 | 
						||
| 
								 | 
							
								    "MapperProperty",
							 | 
						||
| 
								 | 
							
								    "PropComparator",
							 | 
						||
| 
								 | 
							
								    "StrategizedProperty",
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ORMStatementRole(roles.StatementRole):
							 | 
						||
| 
								 | 
							
								    _role_name = (
							 | 
						||
| 
								 | 
							
								        "Executable SQL or text() construct, including ORM " "aware objects"
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ORMColumnsClauseRole(roles.ColumnsClauseRole):
							 | 
						||
| 
								 | 
							
								    _role_name = "ORM mapped entity, aliased entity, or Column expression"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ORMEntityColumnsClauseRole(ORMColumnsClauseRole):
							 | 
						||
| 
								 | 
							
								    _role_name = "ORM mapped or aliased entity"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ORMFromClauseRole(roles.StrictFromClauseRole):
							 | 
						||
| 
								 | 
							
								    _role_name = "ORM mapped entity, aliased entity, or FROM expression"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@inspection._self_inspects
							 | 
						||
| 
								 | 
							
								class MapperProperty(
							 | 
						||
| 
								 | 
							
								    HasCacheKey, _MappedAttribute, InspectionAttr, util.MemoizedSlots
							 | 
						||
| 
								 | 
							
								):
							 | 
						||
| 
								 | 
							
								    """Represent a particular class attribute mapped by :class:`_orm.Mapper`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The most common occurrences of :class:`.MapperProperty` are the
							 | 
						||
| 
								 | 
							
								    mapped :class:`_schema.Column`, which is represented in a mapping as
							 | 
						||
| 
								 | 
							
								    an instance of :class:`.ColumnProperty`,
							 | 
						||
| 
								 | 
							
								    and a reference to another class produced by :func:`_orm.relationship`,
							 | 
						||
| 
								 | 
							
								    represented in the mapping as an instance of
							 | 
						||
| 
								 | 
							
								    :class:`.RelationshipProperty`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = (
							 | 
						||
| 
								 | 
							
								        "_configure_started",
							 | 
						||
| 
								 | 
							
								        "_configure_finished",
							 | 
						||
| 
								 | 
							
								        "parent",
							 | 
						||
| 
								 | 
							
								        "key",
							 | 
						||
| 
								 | 
							
								        "info",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _cache_key_traversal = [
							 | 
						||
| 
								 | 
							
								        ("parent", visitors.ExtendedInternalTraversal.dp_has_cache_key),
							 | 
						||
| 
								 | 
							
								        ("key", visitors.ExtendedInternalTraversal.dp_string),
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    cascade = frozenset()
							 | 
						||
| 
								 | 
							
								    """The set of 'cascade' attribute names.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This collection is checked before the 'cascade_iterator' method is called.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The collection typically only applies to a RelationshipProperty.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_property = True
							 | 
						||
| 
								 | 
							
								    """Part of the InspectionAttr interface; states this object is a
							 | 
						||
| 
								 | 
							
								    mapper property.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def _links_to_entity(self):
							 | 
						||
| 
								 | 
							
								        """True if this MapperProperty refers to a mapped entity.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Should only be True for RelationshipProperty, False for all others.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        raise NotImplementedError()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _memoized_attr_info(self):
							 | 
						||
| 
								 | 
							
								        """Info dictionary associated with the object, allowing user-defined
							 | 
						||
| 
								 | 
							
								        data to be associated with this :class:`.InspectionAttr`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The dictionary is generated when first accessed.  Alternatively,
							 | 
						||
| 
								 | 
							
								        it can be specified as a constructor argument to the
							 | 
						||
| 
								 | 
							
								        :func:`.column_property`, :func:`_orm.relationship`, or
							 | 
						||
| 
								 | 
							
								        :func:`.composite`
							 | 
						||
| 
								 | 
							
								        functions.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionchanged:: 1.0.0 :attr:`.MapperProperty.info` is also
							 | 
						||
| 
								 | 
							
								           available on extension types via the
							 | 
						||
| 
								 | 
							
								           :attr:`.InspectionAttrInfo.info` attribute, so that it can apply
							 | 
						||
| 
								 | 
							
								           to a wider variety of ORM and extension constructs.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`.QueryableAttribute.info`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`.SchemaItem.info`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def setup(self, context, query_entity, path, adapter, **kwargs):
							 | 
						||
| 
								 | 
							
								        """Called by Query for the purposes of constructing a SQL statement.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Each MapperProperty associated with the target mapper processes the
							 | 
						||
| 
								 | 
							
								        statement referenced by the query context, adding columns and/or
							 | 
						||
| 
								 | 
							
								        criterion as appropriate.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def create_row_processor(
							 | 
						||
| 
								 | 
							
								        self, context, query_entity, path, mapper, result, adapter, populators
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """Produce row processing functions and append to the given
							 | 
						||
| 
								 | 
							
								        set of populators lists.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def cascade_iterator(
							 | 
						||
| 
								 | 
							
								        self, type_, state, dict_, visited_states, halt_on=None
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """Iterate through instances related to the given instance for
							 | 
						||
| 
								 | 
							
								        a particular 'cascade', starting with this MapperProperty.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Return an iterator3-tuples (instance, mapper, state).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Note that the 'cascade' collection on this MapperProperty is
							 | 
						||
| 
								 | 
							
								        checked first for the given type before cascade_iterator is called.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method typically only applies to RelationshipProperty.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return iter(())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def set_parent(self, parent, init):
							 | 
						||
| 
								 | 
							
								        """Set the parent mapper that references this MapperProperty.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method is overridden by some subclasses to perform extra
							 | 
						||
| 
								 | 
							
								        setup when the mapper is first known.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        self.parent = parent
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def instrument_class(self, mapper):
							 | 
						||
| 
								 | 
							
								        """Hook called by the Mapper to the property to initiate
							 | 
						||
| 
								 | 
							
								        instrumentation of the class attribute managed by this
							 | 
						||
| 
								 | 
							
								        MapperProperty.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The MapperProperty here will typically call out to the
							 | 
						||
| 
								 | 
							
								        attributes module to set up an InstrumentedAttribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This step is the first of two steps to set up an InstrumentedAttribute,
							 | 
						||
| 
								 | 
							
								        and is called early in the mapper setup process.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The second step is typically the init_class_attribute step,
							 | 
						||
| 
								 | 
							
								        called from StrategizedProperty via the post_instrument_class()
							 | 
						||
| 
								 | 
							
								        hook.  This step assigns additional state to the InstrumentedAttribute
							 | 
						||
| 
								 | 
							
								        (specifically the "impl") which has been determined after the
							 | 
						||
| 
								 | 
							
								        MapperProperty has determined what kind of persistence
							 | 
						||
| 
								 | 
							
								        management it needs to do (e.g. scalar, object, collection, etc).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self):
							 | 
						||
| 
								 | 
							
								        self._configure_started = False
							 | 
						||
| 
								 | 
							
								        self._configure_finished = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def init(self):
							 | 
						||
| 
								 | 
							
								        """Called after all mappers are created to assemble
							 | 
						||
| 
								 | 
							
								        relationships between mappers and perform other post-mapper-creation
							 | 
						||
| 
								 | 
							
								        initialization steps.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        self._configure_started = True
							 | 
						||
| 
								 | 
							
								        self.do_init()
							 | 
						||
| 
								 | 
							
								        self._configure_finished = True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def class_attribute(self):
							 | 
						||
| 
								 | 
							
								        """Return the class-bound descriptor corresponding to this
							 | 
						||
| 
								 | 
							
								        :class:`.MapperProperty`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This is basically a ``getattr()`` call::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return getattr(self.parent.class_, self.key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        I.e. if this :class:`.MapperProperty` were named ``addresses``,
							 | 
						||
| 
								 | 
							
								        and the class to which it is mapped is ``User``, this sequence
							 | 
						||
| 
								 | 
							
								        is possible::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            >>> from sqlalchemy import inspect
							 | 
						||
| 
								 | 
							
								            >>> mapper = inspect(User)
							 | 
						||
| 
								 | 
							
								            >>> addresses_property = mapper.attrs.addresses
							 | 
						||
| 
								 | 
							
								            >>> addresses_property.class_attribute is User.addresses
							 | 
						||
| 
								 | 
							
								            True
							 | 
						||
| 
								 | 
							
								            >>> User.addresses.property is addresses_property
							 | 
						||
| 
								 | 
							
								            True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return getattr(self.parent.class_, self.key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def do_init(self):
							 | 
						||
| 
								 | 
							
								        """Perform subclass-specific initialization post-mapper-creation
							 | 
						||
| 
								 | 
							
								        steps.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This is a template method called by the ``MapperProperty``
							 | 
						||
| 
								 | 
							
								        object's init() method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def post_instrument_class(self, mapper):
							 | 
						||
| 
								 | 
							
								        """Perform instrumentation adjustments that need to occur
							 | 
						||
| 
								 | 
							
								        after init() has completed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The given Mapper is the Mapper invoking the operation, which
							 | 
						||
| 
								 | 
							
								        may not be the same Mapper as self.parent in an inheritance
							 | 
						||
| 
								 | 
							
								        scenario; however, Mapper will always at least be a sub-mapper of
							 | 
						||
| 
								 | 
							
								        self.parent.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method is typically used by StrategizedProperty, which delegates
							 | 
						||
| 
								 | 
							
								        it to LoaderStrategy.init_class_attribute() to perform final setup
							 | 
						||
| 
								 | 
							
								        on the class-bound InstrumentedAttribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def merge(
							 | 
						||
| 
								 | 
							
								        self,
							 | 
						||
| 
								 | 
							
								        session,
							 | 
						||
| 
								 | 
							
								        source_state,
							 | 
						||
| 
								 | 
							
								        source_dict,
							 | 
						||
| 
								 | 
							
								        dest_state,
							 | 
						||
| 
								 | 
							
								        dest_dict,
							 | 
						||
| 
								 | 
							
								        load,
							 | 
						||
| 
								 | 
							
								        _recursive,
							 | 
						||
| 
								 | 
							
								        _resolve_conflict_map,
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """Merge the attribute represented by this ``MapperProperty``
							 | 
						||
| 
								 | 
							
								        from source to destination object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __repr__(self):
							 | 
						||
| 
								 | 
							
								        return "<%s at 0x%x; %s>" % (
							 | 
						||
| 
								 | 
							
								            self.__class__.__name__,
							 | 
						||
| 
								 | 
							
								            id(self),
							 | 
						||
| 
								 | 
							
								            getattr(self, "key", "no key"),
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@inspection._self_inspects
							 | 
						||
| 
								 | 
							
								class PropComparator(operators.ColumnOperators):
							 | 
						||
| 
								 | 
							
								    r"""Defines SQL operators for :class:`.MapperProperty` objects.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    SQLAlchemy allows for operators to
							 | 
						||
| 
								 | 
							
								    be redefined at both the Core and ORM level.  :class:`.PropComparator`
							 | 
						||
| 
								 | 
							
								    is the base class of operator redefinition for ORM-level operations,
							 | 
						||
| 
								 | 
							
								    including those of :class:`.ColumnProperty`,
							 | 
						||
| 
								 | 
							
								    :class:`.RelationshipProperty`, and :class:`.CompositeProperty`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. note:: With the advent of Hybrid properties introduced in SQLAlchemy
							 | 
						||
| 
								 | 
							
								       0.7, as well as Core-level operator redefinition in
							 | 
						||
| 
								 | 
							
								       SQLAlchemy 0.8, the use case for user-defined :class:`.PropComparator`
							 | 
						||
| 
								 | 
							
								       instances is extremely rare.  See :ref:`hybrids_toplevel` as well
							 | 
						||
| 
								 | 
							
								       as :ref:`types_operators`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    User-defined subclasses of :class:`.PropComparator` may be created. The
							 | 
						||
| 
								 | 
							
								    built-in Python comparison and math operator methods, such as
							 | 
						||
| 
								 | 
							
								    :meth:`.operators.ColumnOperators.__eq__`,
							 | 
						||
| 
								 | 
							
								    :meth:`.operators.ColumnOperators.__lt__`, and
							 | 
						||
| 
								 | 
							
								    :meth:`.operators.ColumnOperators.__add__`, can be overridden to provide
							 | 
						||
| 
								 | 
							
								    new operator behavior. The custom :class:`.PropComparator` is passed to
							 | 
						||
| 
								 | 
							
								    the :class:`.MapperProperty` instance via the ``comparator_factory``
							 | 
						||
| 
								 | 
							
								    argument. In each case,
							 | 
						||
| 
								 | 
							
								    the appropriate subclass of :class:`.PropComparator` should be used::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # definition of custom PropComparator subclasses
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        from sqlalchemy.orm.properties import \
							 | 
						||
| 
								 | 
							
								                                ColumnProperty,\
							 | 
						||
| 
								 | 
							
								                                CompositeProperty,\
							 | 
						||
| 
								 | 
							
								                                RelationshipProperty
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        class MyColumnComparator(ColumnProperty.Comparator):
							 | 
						||
| 
								 | 
							
								            def __eq__(self, other):
							 | 
						||
| 
								 | 
							
								                return self.__clause_element__() == other
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        class MyRelationshipComparator(RelationshipProperty.Comparator):
							 | 
						||
| 
								 | 
							
								            def any(self, expression):
							 | 
						||
| 
								 | 
							
								                "define the 'any' operation"
							 | 
						||
| 
								 | 
							
								                # ...
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        class MyCompositeComparator(CompositeProperty.Comparator):
							 | 
						||
| 
								 | 
							
								            def __gt__(self, other):
							 | 
						||
| 
								 | 
							
								                "redefine the 'greater than' operation"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                return sql.and_(*[a>b for a, b in
							 | 
						||
| 
								 | 
							
								                                  zip(self.__clause_element__().clauses,
							 | 
						||
| 
								 | 
							
								                                      other.__composite_values__())])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # application of custom PropComparator subclasses
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        from sqlalchemy.orm import column_property, relationship, composite
							 | 
						||
| 
								 | 
							
								        from sqlalchemy import Column, String
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        class SomeMappedClass(Base):
							 | 
						||
| 
								 | 
							
								            some_column = column_property(Column("some_column", String),
							 | 
						||
| 
								 | 
							
								                                comparator_factory=MyColumnComparator)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            some_relationship = relationship(SomeOtherClass,
							 | 
						||
| 
								 | 
							
								                                comparator_factory=MyRelationshipComparator)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            some_composite = composite(
							 | 
						||
| 
								 | 
							
								                    Column("a", String), Column("b", String),
							 | 
						||
| 
								 | 
							
								                    comparator_factory=MyCompositeComparator
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Note that for column-level operator redefinition, it's usually
							 | 
						||
| 
								 | 
							
								    simpler to define the operators at the Core level, using the
							 | 
						||
| 
								 | 
							
								    :attr:`.TypeEngine.comparator_factory` attribute.  See
							 | 
						||
| 
								 | 
							
								    :ref:`types_operators` for more detail.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :class:`.ColumnProperty.Comparator`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :class:`.RelationshipProperty.Comparator`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :class:`.CompositeProperty.Comparator`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :class:`.ColumnOperators`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :ref:`types_operators`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :attr:`.TypeEngine.comparator_factory`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = "prop", "property", "_parententity", "_adapt_to_entity"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __visit_name__ = "orm_prop_comparator"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(
							 | 
						||
| 
								 | 
							
								        self,
							 | 
						||
| 
								 | 
							
								        prop,
							 | 
						||
| 
								 | 
							
								        parentmapper,
							 | 
						||
| 
								 | 
							
								        adapt_to_entity=None,
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        self.prop = self.property = prop
							 | 
						||
| 
								 | 
							
								        self._parententity = adapt_to_entity or parentmapper
							 | 
						||
| 
								 | 
							
								        self._adapt_to_entity = adapt_to_entity
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __clause_element__(self):
							 | 
						||
| 
								 | 
							
								        raise NotImplementedError("%r" % self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _bulk_update_tuples(self, value):
							 | 
						||
| 
								 | 
							
								        """Receive a SQL expression that represents a value in the SET
							 | 
						||
| 
								 | 
							
								        clause of an UPDATE statement.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Return a tuple that can be passed to a :class:`_expression.Update`
							 | 
						||
| 
								 | 
							
								        construct.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return [(self.__clause_element__(), value)]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def adapt_to_entity(self, adapt_to_entity):
							 | 
						||
| 
								 | 
							
								        """Return a copy of this PropComparator which will use the given
							 | 
						||
| 
								 | 
							
								        :class:`.AliasedInsp` to produce corresponding expressions.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return self.__class__(self.prop, self._parententity, adapt_to_entity)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def _parentmapper(self):
							 | 
						||
| 
								 | 
							
								        """legacy; this is renamed to _parententity to be
							 | 
						||
| 
								 | 
							
								        compatible with QueryableAttribute."""
							 | 
						||
| 
								 | 
							
								        return inspect(self._parententity).mapper
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def _propagate_attrs(self):
							 | 
						||
| 
								 | 
							
								        # this suits the case in coercions where we don't actually
							 | 
						||
| 
								 | 
							
								        # call ``__clause_element__()`` but still need to get
							 | 
						||
| 
								 | 
							
								        # resolved._propagate_attrs.  See #6558.
							 | 
						||
| 
								 | 
							
								        return util.immutabledict(
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                "compile_state_plugin": "orm",
							 | 
						||
| 
								 | 
							
								                "plugin_subject": self._parentmapper,
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def adapter(self):
							 | 
						||
| 
								 | 
							
								        """Produce a callable that adapts column expressions
							 | 
						||
| 
								 | 
							
								        to suit an aliased version of this comparator.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if self._adapt_to_entity is None:
							 | 
						||
| 
								 | 
							
								            return None
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return self._adapt_to_entity._adapt_element
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def info(self):
							 | 
						||
| 
								 | 
							
								        return self.property.info
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def any_op(a, b, **kwargs):
							 | 
						||
| 
								 | 
							
								        return a.any(b, **kwargs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def has_op(a, b, **kwargs):
							 | 
						||
| 
								 | 
							
								        return a.has(b, **kwargs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def of_type_op(a, class_):
							 | 
						||
| 
								 | 
							
								        return a.of_type(class_)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def of_type(self, class_):
							 | 
						||
| 
								 | 
							
								        r"""Redefine this object in terms of a polymorphic subclass,
							 | 
						||
| 
								 | 
							
								        :func:`_orm.with_polymorphic` construct, or :func:`_orm.aliased`
							 | 
						||
| 
								 | 
							
								        construct.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Returns a new PropComparator from which further criterion can be
							 | 
						||
| 
								 | 
							
								        evaluated.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        e.g.::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            query.join(Company.employees.of_type(Engineer)).\
							 | 
						||
| 
								 | 
							
								               filter(Engineer.name=='foo')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param \class_: a class or mapper indicating that criterion will be
							 | 
						||
| 
								 | 
							
								            against this specific subclass.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :ref:`queryguide_join_onclause` - in the :ref:`queryguide_toplevel`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :ref:`inheritance_of_type`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self.operate(PropComparator.of_type_op, class_)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def and_(self, *criteria):
							 | 
						||
| 
								 | 
							
								        """Add additional criteria to the ON clause that's represented by this
							 | 
						||
| 
								 | 
							
								        relationship attribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        E.g.::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            stmt = select(User).join(
							 | 
						||
| 
								 | 
							
								                User.addresses.and_(Address.email_address != 'foo')
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            stmt = select(User).options(
							 | 
						||
| 
								 | 
							
								                joinedload(User.addresses.and_(Address.email_address != 'foo'))
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :ref:`orm_queryguide_join_on_augmented`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :ref:`loader_option_criteria`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :func:`.with_loader_criteria`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return self.operate(operators.and_, *criteria)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def any(self, criterion=None, **kwargs):
							 | 
						||
| 
								 | 
							
								        r"""Return true if this collection contains any member that meets the
							 | 
						||
| 
								 | 
							
								        given criterion.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The usual implementation of ``any()`` is
							 | 
						||
| 
								 | 
							
								        :meth:`.RelationshipProperty.Comparator.any`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param criterion: an optional ClauseElement formulated against the
							 | 
						||
| 
								 | 
							
								          member class' table or attributes.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param \**kwargs: key/value pairs corresponding to member class
							 | 
						||
| 
								 | 
							
								          attribute names which will be compared via equality to the
							 | 
						||
| 
								 | 
							
								          corresponding values.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self.operate(PropComparator.any_op, criterion, **kwargs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def has(self, criterion=None, **kwargs):
							 | 
						||
| 
								 | 
							
								        r"""Return true if this element references a member which meets the
							 | 
						||
| 
								 | 
							
								        given criterion.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The usual implementation of ``has()`` is
							 | 
						||
| 
								 | 
							
								        :meth:`.RelationshipProperty.Comparator.has`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param criterion: an optional ClauseElement formulated against the
							 | 
						||
| 
								 | 
							
								          member class' table or attributes.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param \**kwargs: key/value pairs corresponding to member class
							 | 
						||
| 
								 | 
							
								          attribute names which will be compared via equality to the
							 | 
						||
| 
								 | 
							
								          corresponding values.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self.operate(PropComparator.has_op, criterion, **kwargs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class StrategizedProperty(MapperProperty):
							 | 
						||
| 
								 | 
							
								    """A MapperProperty which uses selectable strategies to affect
							 | 
						||
| 
								 | 
							
								    loading behavior.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    There is a single strategy selected by default.  Alternate
							 | 
						||
| 
								 | 
							
								    strategies can be selected at Query time through the usage of
							 | 
						||
| 
								 | 
							
								    ``StrategizedOption`` objects via the Query.options() method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The mechanics of StrategizedProperty are used for every Query
							 | 
						||
| 
								 | 
							
								    invocation for every mapped attribute participating in that Query,
							 | 
						||
| 
								 | 
							
								    to determine first how the attribute will be rendered in SQL
							 | 
						||
| 
								 | 
							
								    and secondly how the attribute will retrieve a value from a result
							 | 
						||
| 
								 | 
							
								    row and apply it to a mapped object.  The routines here are very
							 | 
						||
| 
								 | 
							
								    performance-critical.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = (
							 | 
						||
| 
								 | 
							
								        "_strategies",
							 | 
						||
| 
								 | 
							
								        "strategy",
							 | 
						||
| 
								 | 
							
								        "_wildcard_token",
							 | 
						||
| 
								 | 
							
								        "_default_path_loader_key",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    inherit_cache = True
							 | 
						||
| 
								 | 
							
								    strategy_wildcard_key = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _memoized_attr__wildcard_token(self):
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            "%s:%s"
							 | 
						||
| 
								 | 
							
								            % (self.strategy_wildcard_key, path_registry._WILDCARD_TOKEN),
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _memoized_attr__default_path_loader_key(self):
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            "loader",
							 | 
						||
| 
								 | 
							
								            (
							 | 
						||
| 
								 | 
							
								                "%s:%s"
							 | 
						||
| 
								 | 
							
								                % (self.strategy_wildcard_key, path_registry._DEFAULT_TOKEN),
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _get_context_loader(self, context, path):
							 | 
						||
| 
								 | 
							
								        load = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        search_path = path[self]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # search among: exact match, "attr.*", "default" strategy
							 | 
						||
| 
								 | 
							
								        # if any.
							 | 
						||
| 
								 | 
							
								        for path_key in (
							 | 
						||
| 
								 | 
							
								            search_path._loader_key,
							 | 
						||
| 
								 | 
							
								            search_path._wildcard_path_loader_key,
							 | 
						||
| 
								 | 
							
								            search_path._default_path_loader_key,
							 | 
						||
| 
								 | 
							
								        ):
							 | 
						||
| 
								 | 
							
								            if path_key in context.attributes:
							 | 
						||
| 
								 | 
							
								                load = context.attributes[path_key]
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return load
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _get_strategy(self, key):
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            return self._strategies[key]
							 | 
						||
| 
								 | 
							
								        except KeyError:
							 | 
						||
| 
								 | 
							
								            pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # run outside to prevent transfer of exception context
							 | 
						||
| 
								 | 
							
								        cls = self._strategy_lookup(self, *key)
							 | 
						||
| 
								 | 
							
								        # this previously was setting self._strategies[cls], that's
							 | 
						||
| 
								 | 
							
								        # a bad idea; should use strategy key at all times because every
							 | 
						||
| 
								 | 
							
								        # strategy has multiple keys at this point
							 | 
						||
| 
								 | 
							
								        self._strategies[key] = strategy = cls(self, key)
							 | 
						||
| 
								 | 
							
								        return strategy
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def setup(self, context, query_entity, path, adapter, **kwargs):
							 | 
						||
| 
								 | 
							
								        loader = self._get_context_loader(context, path)
							 | 
						||
| 
								 | 
							
								        if loader and loader.strategy:
							 | 
						||
| 
								 | 
							
								            strat = self._get_strategy(loader.strategy)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            strat = self.strategy
							 | 
						||
| 
								 | 
							
								        strat.setup_query(
							 | 
						||
| 
								 | 
							
								            context, query_entity, path, loader, adapter, **kwargs
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def create_row_processor(
							 | 
						||
| 
								 | 
							
								        self, context, query_entity, path, mapper, result, adapter, populators
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        loader = self._get_context_loader(context, path)
							 | 
						||
| 
								 | 
							
								        if loader and loader.strategy:
							 | 
						||
| 
								 | 
							
								            strat = self._get_strategy(loader.strategy)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            strat = self.strategy
							 | 
						||
| 
								 | 
							
								        strat.create_row_processor(
							 | 
						||
| 
								 | 
							
								            context,
							 | 
						||
| 
								 | 
							
								            query_entity,
							 | 
						||
| 
								 | 
							
								            path,
							 | 
						||
| 
								 | 
							
								            loader,
							 | 
						||
| 
								 | 
							
								            mapper,
							 | 
						||
| 
								 | 
							
								            result,
							 | 
						||
| 
								 | 
							
								            adapter,
							 | 
						||
| 
								 | 
							
								            populators,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def do_init(self):
							 | 
						||
| 
								 | 
							
								        self._strategies = {}
							 | 
						||
| 
								 | 
							
								        self.strategy = self._get_strategy(self.strategy_key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def post_instrument_class(self, mapper):
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								            not self.parent.non_primary
							 | 
						||
| 
								 | 
							
								            and not mapper.class_manager._attr_has_impl(self.key)
							 | 
						||
| 
								 | 
							
								        ):
							 | 
						||
| 
								 | 
							
								            self.strategy.init_class_attribute(mapper)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _all_strategies = collections.defaultdict(dict)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def strategy_for(cls, **kw):
							 | 
						||
| 
								 | 
							
								        def decorate(dec_cls):
							 | 
						||
| 
								 | 
							
								            # ensure each subclass of the strategy has its
							 | 
						||
| 
								 | 
							
								            # own _strategy_keys collection
							 | 
						||
| 
								 | 
							
								            if "_strategy_keys" not in dec_cls.__dict__:
							 | 
						||
| 
								 | 
							
								                dec_cls._strategy_keys = []
							 | 
						||
| 
								 | 
							
								            key = tuple(sorted(kw.items()))
							 | 
						||
| 
								 | 
							
								            cls._all_strategies[cls][key] = dec_cls
							 | 
						||
| 
								 | 
							
								            dec_cls._strategy_keys.append(key)
							 | 
						||
| 
								 | 
							
								            return dec_cls
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return decorate
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _strategy_lookup(cls, requesting_property, *key):
							 | 
						||
| 
								 | 
							
								        requesting_property.parent._with_polymorphic_mappers
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for prop_cls in cls.__mro__:
							 | 
						||
| 
								 | 
							
								            if prop_cls in cls._all_strategies:
							 | 
						||
| 
								 | 
							
								                strategies = cls._all_strategies[prop_cls]
							 | 
						||
| 
								 | 
							
								                try:
							 | 
						||
| 
								 | 
							
								                    return strategies[key]
							 | 
						||
| 
								 | 
							
								                except KeyError:
							 | 
						||
| 
								 | 
							
								                    pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for property_type, strats in cls._all_strategies.items():
							 | 
						||
| 
								 | 
							
								            if key in strats:
							 | 
						||
| 
								 | 
							
								                intended_property_type = property_type
							 | 
						||
| 
								 | 
							
								                actual_strategy = strats[key]
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            intended_property_type = None
							 | 
						||
| 
								 | 
							
								            actual_strategy = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        raise orm_exc.LoaderStrategyException(
							 | 
						||
| 
								 | 
							
								            cls,
							 | 
						||
| 
								 | 
							
								            requesting_property,
							 | 
						||
| 
								 | 
							
								            intended_property_type,
							 | 
						||
| 
								 | 
							
								            actual_strategy,
							 | 
						||
| 
								 | 
							
								            key,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ORMOption(ExecutableOption):
							 | 
						||
| 
								 | 
							
								    """Base class for option objects that are passed to ORM queries.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    These options may be consumed by :meth:`.Query.options`,
							 | 
						||
| 
								 | 
							
								    :meth:`.Select.options`, or in a more general sense by any
							 | 
						||
| 
								 | 
							
								    :meth:`.Executable.options` method.   They are interpreted at
							 | 
						||
| 
								 | 
							
								    statement compile time or execution time in modern use.  The
							 | 
						||
| 
								 | 
							
								    deprecated :class:`.MapperOption` is consumed at ORM query construction
							 | 
						||
| 
								 | 
							
								    time.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = ()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _is_legacy_option = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    propagate_to_loaders = False
							 | 
						||
| 
								 | 
							
								    """if True, indicate this option should be carried along
							 | 
						||
| 
								 | 
							
								    to "secondary" SELECT statements that occur for relationship
							 | 
						||
| 
								 | 
							
								    lazy loaders as well as attribute load / refresh operations.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _is_compile_state = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _is_criteria_option = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _is_strategy_option = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CompileStateOption(HasCacheKey, ORMOption):
							 | 
						||
| 
								 | 
							
								    """base for :class:`.ORMOption` classes that affect the compilation of
							 | 
						||
| 
								 | 
							
								    a SQL query and therefore need to be part of the cache key.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. note::  :class:`.CompileStateOption` is generally non-public and
							 | 
						||
| 
								 | 
							
								       should not be used as a base class for user-defined options; instead,
							 | 
						||
| 
								 | 
							
								       use :class:`.UserDefinedOption`, which is easier to use as it does not
							 | 
						||
| 
								 | 
							
								       interact with ORM compilation internals or caching.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :class:`.CompileStateOption` defines an internal attribute
							 | 
						||
| 
								 | 
							
								    ``_is_compile_state=True`` which has the effect of the ORM compilation
							 | 
						||
| 
								 | 
							
								    routines for SELECT and other statements will call upon these options when
							 | 
						||
| 
								 | 
							
								    a SQL string is being compiled. As such, these classes implement
							 | 
						||
| 
								 | 
							
								    :class:`.HasCacheKey` and need to provide robust ``_cache_key_traversal``
							 | 
						||
| 
								 | 
							
								    structures.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The :class:`.CompileStateOption` class is used to implement the ORM
							 | 
						||
| 
								 | 
							
								    :class:`.LoaderOption` and :class:`.CriteriaOption` classes.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 1.4.28
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _is_compile_state = True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def process_compile_state(self, compile_state):
							 | 
						||
| 
								 | 
							
								        """Apply a modification to a given :class:`.CompileState`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def process_compile_state_replaced_entities(
							 | 
						||
| 
								 | 
							
								        self, compile_state, mapper_entities
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """Apply a modification to a given :class:`.CompileState`,
							 | 
						||
| 
								 | 
							
								        given entities that were replaced by with_only_columns() or
							 | 
						||
| 
								 | 
							
								        with_entities().
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4.19
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class LoaderOption(CompileStateOption):
							 | 
						||
| 
								 | 
							
								    """Describe a loader modification to an ORM statement at compilation time.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def process_compile_state_replaced_entities(
							 | 
						||
| 
								 | 
							
								        self, compile_state, mapper_entities
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """Apply a modification to a given :class:`.CompileState`,
							 | 
						||
| 
								 | 
							
								        given entities that were replaced by with_only_columns() or
							 | 
						||
| 
								 | 
							
								        with_entities().
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4.19
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        self.process_compile_state(compile_state)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def process_compile_state(self, compile_state):
							 | 
						||
| 
								 | 
							
								        """Apply a modification to a given :class:`.CompileState`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CriteriaOption(CompileStateOption):
							 | 
						||
| 
								 | 
							
								    """Describe a WHERE criteria modification to an ORM statement at
							 | 
						||
| 
								 | 
							
								    compilation time.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _is_criteria_option = True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def process_compile_state(self, compile_state):
							 | 
						||
| 
								 | 
							
								        """Apply a modification to a given :class:`.CompileState`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def get_global_criteria(self, attributes):
							 | 
						||
| 
								 | 
							
								        """update additional entity criteria options in the given
							 | 
						||
| 
								 | 
							
								        attributes dictionary.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class UserDefinedOption(ORMOption):
							 | 
						||
| 
								 | 
							
								    """Base class for a user-defined option that can be consumed from the
							 | 
						||
| 
								 | 
							
								    :meth:`.SessionEvents.do_orm_execute` event hook.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _is_legacy_option = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    propagate_to_loaders = False
							 | 
						||
| 
								 | 
							
								    """if True, indicate this option should be carried along
							 | 
						||
| 
								 | 
							
								    to "secondary" Query objects produced during lazy loads
							 | 
						||
| 
								 | 
							
								    or refresh operations.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, payload=None):
							 | 
						||
| 
								 | 
							
								        self.payload = payload
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@util.deprecated_cls(
							 | 
						||
| 
								 | 
							
								    "1.4",
							 | 
						||
| 
								 | 
							
								    "The :class:`.MapperOption class is deprecated and will be removed "
							 | 
						||
| 
								 | 
							
								    "in a future release.   For "
							 | 
						||
| 
								 | 
							
								    "modifications to queries on a per-execution basis, use the "
							 | 
						||
| 
								 | 
							
								    ":class:`.UserDefinedOption` class to establish state within a "
							 | 
						||
| 
								 | 
							
								    ":class:`.Query` or other Core statement, then use the "
							 | 
						||
| 
								 | 
							
								    ":meth:`.SessionEvents.before_orm_execute` hook to consume them.",
							 | 
						||
| 
								 | 
							
								    constructor=None,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								class MapperOption(ORMOption):
							 | 
						||
| 
								 | 
							
								    """Describe a modification to a Query"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _is_legacy_option = True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    propagate_to_loaders = False
							 | 
						||
| 
								 | 
							
								    """if True, indicate this option should be carried along
							 | 
						||
| 
								 | 
							
								    to "secondary" Query objects produced during lazy loads
							 | 
						||
| 
								 | 
							
								    or refresh operations.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def process_query(self, query):
							 | 
						||
| 
								 | 
							
								        """Apply a modification to the given :class:`_query.Query`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def process_query_conditionally(self, query):
							 | 
						||
| 
								 | 
							
								        """same as process_query(), except that this option may not
							 | 
						||
| 
								 | 
							
								        apply to the given query.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This is typically applied during a lazy load or scalar refresh
							 | 
						||
| 
								 | 
							
								        operation to propagate options stated in the original Query to the
							 | 
						||
| 
								 | 
							
								        new Query being used for the load.  It occurs for those options that
							 | 
						||
| 
								 | 
							
								        specify propagate_to_loaders=True.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.process_query(query)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class LoaderStrategy(object):
							 | 
						||
| 
								 | 
							
								    """Describe the loading behavior of a StrategizedProperty object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The ``LoaderStrategy`` interacts with the querying process in three
							 | 
						||
| 
								 | 
							
								    ways:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    * it controls the configuration of the ``InstrumentedAttribute``
							 | 
						||
| 
								 | 
							
								      placed on a class to handle the behavior of the attribute.  this
							 | 
						||
| 
								 | 
							
								      may involve setting up class-level callable functions to fire
							 | 
						||
| 
								 | 
							
								      off a select operation when the attribute is first accessed
							 | 
						||
| 
								 | 
							
								      (i.e. a lazy load)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    * it processes the ``QueryContext`` at statement construction time,
							 | 
						||
| 
								 | 
							
								      where it can modify the SQL statement that is being produced.
							 | 
						||
| 
								 | 
							
								      For example, simple column attributes will add their represented
							 | 
						||
| 
								 | 
							
								      column to the list of selected columns, a joined eager loader
							 | 
						||
| 
								 | 
							
								      may establish join clauses to add to the statement.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    * It produces "row processor" functions at result fetching time.
							 | 
						||
| 
								 | 
							
								      These "row processor" functions populate a particular attribute
							 | 
						||
| 
								 | 
							
								      on a particular mapped instance.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = (
							 | 
						||
| 
								 | 
							
								        "parent_property",
							 | 
						||
| 
								 | 
							
								        "is_class_level",
							 | 
						||
| 
								 | 
							
								        "parent",
							 | 
						||
| 
								 | 
							
								        "key",
							 | 
						||
| 
								 | 
							
								        "strategy_key",
							 | 
						||
| 
								 | 
							
								        "strategy_opts",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, parent, strategy_key):
							 | 
						||
| 
								 | 
							
								        self.parent_property = parent
							 | 
						||
| 
								 | 
							
								        self.is_class_level = False
							 | 
						||
| 
								 | 
							
								        self.parent = self.parent_property.parent
							 | 
						||
| 
								 | 
							
								        self.key = self.parent_property.key
							 | 
						||
| 
								 | 
							
								        self.strategy_key = strategy_key
							 | 
						||
| 
								 | 
							
								        self.strategy_opts = dict(strategy_key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def init_class_attribute(self, mapper):
							 | 
						||
| 
								 | 
							
								        pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def setup_query(
							 | 
						||
| 
								 | 
							
								        self, compile_state, query_entity, path, loadopt, adapter, **kwargs
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """Establish column and other state for a given QueryContext.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method fulfills the contract specified by MapperProperty.setup().
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        StrategizedProperty delegates its setup() method
							 | 
						||
| 
								 | 
							
								        directly to this method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def create_row_processor(
							 | 
						||
| 
								 | 
							
								        self,
							 | 
						||
| 
								 | 
							
								        context,
							 | 
						||
| 
								 | 
							
								        query_entity,
							 | 
						||
| 
								 | 
							
								        path,
							 | 
						||
| 
								 | 
							
								        loadopt,
							 | 
						||
| 
								 | 
							
								        mapper,
							 | 
						||
| 
								 | 
							
								        result,
							 | 
						||
| 
								 | 
							
								        adapter,
							 | 
						||
| 
								 | 
							
								        populators,
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """Establish row processing functions for a given QueryContext.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method fulfills the contract specified by
							 | 
						||
| 
								 | 
							
								        MapperProperty.create_row_processor().
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        StrategizedProperty delegates its create_row_processor() method
							 | 
						||
| 
								 | 
							
								        directly to this method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __str__(self):
							 | 
						||
| 
								 | 
							
								        return str(self.parent_property)
							 |