]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- column_property() and synonym() both accept comparator_factory argument, allowing
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 21 Aug 2008 18:10:35 +0000 (18:10 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 21 Aug 2008 18:10:35 +0000 (18:10 +0000)
custom comparison functionality
- made the mapper's checks for user-based descriptors when defining synonym or comparable property
stronger, such that a synonym can be used with declarative without having a user-based descriptor

lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/properties.py

index e405d76a2756ae171204b939e819130199c324f0..da9134b112ee7520b6153ef5bbe6c7df10d55759 100644 (file)
@@ -642,7 +642,7 @@ def mapper(class_, local_table=None, *args, **params):
     """
     return Mapper(class_, local_table, *args, **params)
 
-def synonym(name, map_column=False, descriptor=None, proxy=False):
+def synonym(name, map_column=False, descriptor=None, comparator_factory=None, proxy=False):
     """Set up `name` as a synonym to another mapped property.
 
     Used with the ``properties`` dictionary sent to  [sqlalchemy.orm#mapper()].
@@ -684,7 +684,7 @@ def synonym(name, map_column=False, descriptor=None, proxy=False):
     is not already available.
 
     """
-    return SynonymProperty(name, map_column=map_column, descriptor=descriptor)
+    return SynonymProperty(name, map_column=map_column, descriptor=descriptor, comparator_factory=comparator_factory)
 
 def comparable_property(comparator_factory, descriptor=None):
     """Provide query semantics for an unmanaged attribute.
index d1713e6f993eb85ead616bb171679ad220ed1357..921d08b833cd533394929a55de22c557447454a8 100644 (file)
@@ -640,6 +640,9 @@ class Mapper(object):
 
             return getattr(getattr(cls, clskey), key)
 
+    def _is_userland_descriptor(self, obj):
+        return not isinstance(obj, (MapperProperty, attributes.InstrumentedAttribute)) and hasattr(obj, '__get__')
+        
     def _should_exclude(self, name, local):
         """determine whether a particular property should be implicitly present on the class.
 
@@ -648,18 +651,15 @@ class Mapper(object):
 
         """
 
-        def is_userland_descriptor(obj):
-            return not isinstance(obj, attributes.InstrumentedAttribute) and hasattr(obj, '__get__')
-
         # check for descriptors, either local or from
         # an inherited class
         if local:
             if self.class_.__dict__.get(name, None)\
-                and is_userland_descriptor(self.class_.__dict__[name]):
+                and self._is_userland_descriptor(self.class_.__dict__[name]):
                 return True
         else:
             if getattr(self.class_, name, None)\
-                and is_userland_descriptor(getattr(self.class_, name)):
+                and self._is_userland_descriptor(getattr(self.class_, name)):
                 return True
 
         if (self.include_properties is not None and
@@ -786,9 +786,11 @@ class Mapper(object):
 
         elif isinstance(prop, (ComparableProperty, SynonymProperty)) and setparent:
             if prop.descriptor is None:
-                prop.descriptor = getattr(self.class_, key, None)
-                if isinstance(prop.descriptor, Mapper._CompileOnAttr):
-                    prop.descriptor = object.__getattribute__(prop.descriptor, 'existing_prop')
+                desc = getattr(self.class_, key, None)
+                if isinstance(desc, Mapper._CompileOnAttr):
+                    desc = object.__getattribute__(desc, 'existing_prop')
+                if self._is_userland_descriptor(desc):
+                    prop.descriptor = desc
             if getattr(prop, 'map_column', False):
                 if key not in self.mapped_table.c:
                     raise sa_exc.ArgumentError("Can't compile synonym '%s': no column on table '%s' named '%s'"  % (prop.name, self.mapped_table.description, key))
index 3d717cae080487faa2eab83aa79f6dafabb644f6..ceabc27920f275164931df6e681c0e9523d804dc 100644 (file)
@@ -41,7 +41,7 @@ class ColumnProperty(StrategizedProperty):
         self.columns = [expression._labeled(c) for c in columns]
         self.group = kwargs.pop('group', None)
         self.deferred = kwargs.pop('deferred', False)
-        self.comparator_factory = ColumnProperty.ColumnComparator
+        self.comparator_factory = kwargs.pop('comparator_factory', ColumnProperty.ColumnComparator)
         util.set_creation_order(self)
         if self.deferred:
             self.strategy_class = strategies.DeferredColumnLoader
@@ -161,10 +161,11 @@ class CompositeProperty(ColumnProperty):
         return str(self.parent.class_.__name__) + "." + self.key
 
 class SynonymProperty(MapperProperty):
-    def __init__(self, name, map_column=None, descriptor=None):
+    def __init__(self, name, map_column=None, descriptor=None, comparator_factory=None):
         self.name = name
         self.map_column = map_column
         self.descriptor = descriptor
+        self.comparator_factory = comparator_factory
         util.set_creation_order(self)
 
     def setup(self, context, entity, path, adapter, **kwargs):
@@ -192,10 +193,14 @@ class SynonymProperty(MapperProperty):
         def comparator_callable(prop, mapper):
             def comparator():
                 prop = self.parent._get_property(self.key, resolve_synonyms=True)
-                return prop.comparator_factory(prop, mapper)
+                if self.comparator_factory:
+                    return self.comparator_factory(prop, mapper)
+                else:
+                    return prop.comparator_factory(prop, mapper)
             return comparator
 
-        strategies.DefaultColumnLoader(self)._register_attribute(None, None, False, comparator_callable, proxy_property=self.descriptor)
+        strategies.DefaultColumnLoader(self)._register_attribute(
+            None, None, False, comparator_callable, proxy_property=self.descriptor)
 
     def merge(self, session, source, dest, dont_load, _recursive):
         pass