summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-12-09 19:06:22 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2010-12-09 19:06:22 -0500
commit5622cfd5ecd5efe5e8c737be6b2ba0100aaf86b0 (patch)
tree72558e291ebc958b1061404713eccbb3ee74074a /lib/sqlalchemy
parent6e4515948f87a2299461003c709393b68453d2d0 (diff)
downloadsqlalchemy-5622cfd5ecd5efe5e8c737be6b2ba0100aaf86b0.tar.gz
callcount destructo engage
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/event.py4
-rw-r--r--lib/sqlalchemy/orm/interfaces.py23
-rw-r--r--lib/sqlalchemy/orm/mapper.py100
-rw-r--r--lib/sqlalchemy/orm/properties.py10
-rw-r--r--lib/sqlalchemy/orm/state.py21
5 files changed, 96 insertions, 62 deletions
diff --git a/lib/sqlalchemy/event.py b/lib/sqlalchemy/event.py
index ed33bb74c..dce09220c 100644
--- a/lib/sqlalchemy/event.py
+++ b/lib/sqlalchemy/event.py
@@ -204,7 +204,9 @@ class _ListenerCollection(object):
def __call__(self, *args, **kw):
"""Execute this event."""
- for fn in self.parent_listeners + self.listeners:
+ for fn in self.parent_listeners:
+ fn(*args, **kw)
+ for fn in self.listeners:
fn(*args, **kw)
# I'm not entirely thrilled about the overhead here,
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index 5686bdd33..90d105dc9 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -7,11 +7,13 @@
"""
-Semi-private module containing various base classes used throughout the ORM.
+Contains various base classes used throughout the ORM.
-Defines the extension classes :class:`MapperExtension`,
-:class:`SessionExtension`, and :class:`AttributeExtension` as
-well as other user-subclassable extension objects.
+Defines the now deprecated ORM extension classes as well
+as ORM internals.
+
+Other than the deprecated extensions, this module and the
+classes within should be considered mostly private.
"""
@@ -67,6 +69,19 @@ class MapperProperty(object):
"""
+ get_col_value = None
+ """Optional method which converts an attribute value into a per-column
+ value::
+
+ def get_col_value(self, column, value):
+ ...
+
+ Basically used by CompositeProperty.
+
+ The mapper checks this attribute for non-None to reduce callcounts.
+
+ """
+
def setup(self, context, entity, path, adapter, **kwargs):
"""Called by Query for the purposes of constructing a SQL statement.
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 5bd4e0f41..54d6a53e2 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -1262,9 +1262,12 @@ class Mapper(object):
return [self._get_state_attr_by_column(state, dict_, column) for
column in self.primary_key]
- # TODO: improve names?
def _get_state_attr_by_column(self, state, dict_, column, passive=False):
- return self._columntoproperty[column]._getattr(state, dict_, column, passive=passive)
+ prop = self._columntoproperty[column]
+ value = state.manager[prop.key].impl.get(state, dict_, passive=passive)
+ if prop.get_col_value:
+ value = prop.get_col_value(column, value)
+ return value
def _set_state_attr_by_column(self, state, dict_, column, value):
return self._columntoproperty[column]._setattr(state, dict_, value, column)
@@ -1499,9 +1502,10 @@ class Mapper(object):
history = attributes.get_state_history(
state, prop.key, passive=True)
if history.added:
- params[col.key] = \
- prop.get_col_value(col,
- history.added[0])
+ value = history.added[0]
+ if prop.get_col_value:
+ value = prop.get_col_value(col, value)
+ params[col.key] = value
hasdata = True
if hasdata:
update.append((state, state_dict, params, mapper,
@@ -1636,8 +1640,7 @@ class Mapper(object):
pks = mapper._pks_by_table[table]
- isinsert = not has_identity and \
- not row_switch
+ isinsert = not has_identity and not row_switch
params = {}
value_params = {}
@@ -1648,23 +1651,25 @@ class Mapper(object):
if col is mapper.version_id_col:
params[col.key] = \
mapper.version_id_generator(None)
- elif col in pks:
- value = \
- mapper._get_state_attr_by_column(
- state, state_dict, col)
- if value is not None:
- params[col.key] = value
else:
- value = \
- mapper._get_state_attr_by_column(
- state, state_dict, col)
- if ((col.default is None and
- col.server_default is None) or
- value is not None):
- if isinstance(value, sql.ClauseElement):
- value_params[col] = value
- else:
- params[col.key] = value
+ # inline of _get_state_attr_by_column
+ prop = mapper._columntoproperty[col]
+ value = state_dict.get(prop.key, None)
+
+ if prop.get_col_value:
+ value = prop.get_col_value(col, value)
+
+ if value is None:
+ if col.default is None and \
+ col.server_default is None and \
+ col not in pks:
+
+ params[col.key] = value
+ elif isinstance(value, sql.ClauseElement):
+ value_params[col] = value
+ else:
+ params[col.key] = value
+
insert.append((state, state_dict, params, mapper,
connection, value_params))
else:
@@ -1709,9 +1714,10 @@ class Mapper(object):
sql.ClauseElement):
value_params[col] = history.added[0]
else:
- params[col.key] = \
- prop.get_col_value(col,
- history.added[0])
+ value = history.added[0]
+ if prop.get_col_value:
+ value = prop.get_col_value(col, value)
+ params[col.key] = value
if col in pks:
if history.deleted:
@@ -1722,15 +1728,17 @@ class Mapper(object):
if ("pk_cascaded", state, col) in \
uowtransaction.\
attributes:
- params[col._label] = \
- prop.get_col_value(col,
- history.added[0])
+ value = history.added[0]
+ if prop.get_col_value:
+ value = prop.get_col_value(col, value)
+ params[col._label] = value
else:
# use the old value to
# locate the row
- params[col._label] = \
- prop.get_col_value(col,
- history.deleted[0])
+ value = history.deleted[0]
+ if prop.get_col_value:
+ value = prop.get_col_value(col, value)
+ params[col._label] = value
hasdata = True
else:
# row switch logic can reach us here
@@ -1739,16 +1747,17 @@ class Mapper(object):
# attempt to include the pk in the
# update statement
del params[col.key]
- params[col._label] = \
- prop.get_col_value(col,
- history.added[0])
+ value = history.added[0]
+ if prop.get_col_value:
+ value = prop.get_col_value(col, value)
+ params[col._label] = value
else:
hasdata = True
elif col in pks:
- params[col._label] = \
- mapper._get_state_attr_by_column(
- state,
- state_dict, col)
+ value = state.manager[prop.key].impl.get(state, state_dict)
+ if prop.get_col_value:
+ value = prop.get_col_value(col, value)
+ params[col._label] = value
if hasdata:
update.append((state, state_dict, params, mapper,
connection, value_params))
@@ -1840,13 +1849,12 @@ class Mapper(object):
for state, state_dict, mapper, connection, has_identity, \
instance_key, row_switch in tups:
- # expire readonly attributes
- readonly = state.unmodified.intersection(
- p.key for p in mapper._readonly_props
- )
-
- if readonly:
- sessionlib._expire_state(state, state.dict, readonly)
+ if mapper._readonly_props:
+ readonly = state.unmodified_intersection(
+ [p.key for p in mapper._readonly_props]
+ )
+ if readonly:
+ sessionlib._expire_state(state, state.dict, readonly)
# if eager_defaults option is enabled,
# refresh whatever has been expired.
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 953974af3..c2f88f9ed 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -119,9 +119,6 @@ class ColumnProperty(StrategizedProperty):
active_history=self.active_history,
*self.columns)
- def _getattr(self, state, dict_, column, passive=False):
- return state.get_impl(self.key).get(state, dict_, passive=passive)
-
def _getcommitted(self, state, dict_, column, passive=False):
return state.get_impl(self.key).\
get_committed_value(state, dict_, passive=passive)
@@ -143,9 +140,6 @@ class ColumnProperty(StrategizedProperty):
if dest_state.has_identity and self.key not in dest_dict:
dest_state.expire_attributes(dest_dict, [self.key])
- def get_col_value(self, column, value):
- return value
-
class Comparator(PropComparator):
@util.memoized_instancemethod
def __clause_element__(self):
@@ -195,10 +189,6 @@ class CompositeProperty(ColumnProperty):
# which issues assertions that do not apply to CompositeColumnProperty
super(ColumnProperty, self).do_init()
- def _getattr(self, state, dict_, column, passive=False):
- obj = state.get_impl(self.key).get(state, dict_, passive=passive)
- return self.get_col_value(column, obj)
-
def _getcommitted(self, state, dict_, column, passive=False):
# TODO: no coverage here
obj = state.get_impl(self.key).\
diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py
index 668c04f50..3984c0e0c 100644
--- a/lib/sqlalchemy/orm/state.py
+++ b/lib/sqlalchemy/orm/state.py
@@ -118,7 +118,7 @@ class InstanceState(object):
return self.manager.get_impl(key).get_history(self, self.dict, **kwargs)
def get_impl(self, key):
- return self.manager.get_impl(key)
+ return self.manager[key].impl
def get_pending(self, key):
if key not in self.pending:
@@ -298,6 +298,13 @@ class InstanceState(object):
return set(self.manager).difference(self.committed_state)
+ def unmodified_intersection(self, keys):
+ """Return self.unmodified.intersection(keys)."""
+
+ return set(keys).intersection(self.manager).\
+ difference(self.committed_state)
+
+
@property
def unloaded(self):
"""Return the set of keys which do not have a loaded value.
@@ -457,7 +464,19 @@ class MutableAttrInstanceState(InstanceState):
if (key not in self.committed_state or
(key in self.manager.mutable_attributes and
not self.manager[key].impl.check_mutable_modified(self, dict_)))])
+
+ def unmodified_intersection(self, keys):
+ """Return self.unmodified.intersection(keys)."""
+ dict_ = self.dict
+
+ return set([
+ key for key in keys
+ if (key not in self.committed_state or
+ (key in self.manager.mutable_attributes and
+ not self.manager[key].impl.check_mutable_modified(self, dict_)))])
+
+
def _is_really_none(self):
"""do a check modified/resurrect.