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,
"""
-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.
"""
"""
+ 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.
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)
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,
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 = {}
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:
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:
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
# 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))
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.
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)
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):
# 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).\
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:
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.
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.
def test_profile_1_create_tables(self):
self.test_baseline_1_create_tables()
- @profiling.function_call_count(8469)
+ @profiling.function_call_count(7321)
def test_profile_1a_populate(self):
self.test_baseline_1a_populate()
- @profiling.function_call_count(591)
+ @profiling.function_call_count(507)
def test_profile_2_insert(self):
self.test_baseline_2_insert()
"INSERT INTO base (data, type) VALUES (:data, :type)",
[{'data':'s1','type':'sub'}]
),
- CompiledSQL(
- "SELECT sub.counter AS sub_counter, base.counter AS "
- "base_counter FROM base JOIN sub ON base.id = "
- "sub.id WHERE base.id = :param_1",
- lambda ctx:{'param_1':s1.id}
- ),
CompiledSQL(
"INSERT INTO sub (id, sub) VALUES (:id, :sub)",
lambda ctx:{'id':s1.id, 'sub':None}
),
)
-
+ def go():
+ eq_( s1.counter2, 1 )
+ self.assert_sql_execution(
+ testing.db,
+ go,
+ CompiledSQL(
+ "SELECT sub.counter AS sub_counter, base.counter AS base_counter, "
+ "sub.counter2 AS sub_counter2 FROM base JOIN sub ON "
+ "base.id = sub.id WHERE base.id = :param_1",
+ lambda ctx:{u'param_1': s1.id}
+ ),
+ )
+
@testing.resolve_artifact_names
def test_dont_generate_on_none(self):
class Base(_base.ComparableEntity):
"(:id, :sub, :counter)",
lambda ctx:[{'counter': 1, 'sub': None, 'id': s1.id}]
),
- CompiledSQL(
- "SELECT subsub.counter2 AS subsub_counter2, sub.counter2 AS "
- "sub_counter2 FROM base JOIN sub ON base.id = sub.id JOIN "
- "subsub ON sub.id = subsub.id WHERE base.id = :param_1",
- lambda ctx:{u'param_1': s1.id}
- ),
CompiledSQL(
"INSERT INTO subsub (id) VALUES (:id)",
lambda ctx:{'id':s1.id}
),
)
-
-
+
+ def go():
+ eq_(
+ s1.counter2, 1
+ )
+ self.assert_sql_execution(
+ testing.db,
+ go,
+ CompiledSQL(
+ "SELECT subsub.counter2 AS subsub_counter2, "
+ "sub.counter2 AS sub_counter2 FROM subsub, sub "
+ "WHERE :param_1 = sub.id AND sub.id = subsub.id",
+ lambda ctx:{u'param_1': s1.id}
+ ),
+ )
class PKDiscriminatorTest(_base.MappedTest):
@classmethod