summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-12-18 00:24:03 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-12-18 00:24:03 +0000
commitf6068a3522bb92fac18c930eb26798fc4cb1889f (patch)
tree2ce96db7758621f605ea605342a106309e134d56 /lib/sqlalchemy
parent420c098d56e9925b51067711c6817475165c6af2 (diff)
downloadsqlalchemy-f6068a3522bb92fac18c930eb26798fc4cb1889f.tar.gz
- select().as_scalar() will raise an exception if the select does not have
exactly one expression in its columns clause. - added "helper exception" to select.type access, generic functions raise the chance of this happening - a slight behavioral change to attributes is, del'ing an attribute does *not* cause the lazyloader of that attribute to fire off again; the "del" makes the effective value of the attribute "None". To re-trigger the "loader" for an attribute, use session.expire(instance, [attrname]). - fix ormtutorial for IS NULL
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/attributes.py32
-rw-r--r--lib/sqlalchemy/sql/expression.py18
2 files changed, 29 insertions, 21 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index 677167c1b..6d5fae507 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -208,20 +208,22 @@ class AttributeImpl(object):
try:
return state.dict[self.key]
except KeyError:
- callable_ = self._get_callable(state)
- if callable_ is not None:
- if passive:
- return PASSIVE_NORESULT
- value = callable_()
- if value is not ATTR_WAS_SET:
- return self.set_committed_value(state, value)
- else:
- if self.key not in state.dict:
- return self.get(state, passive=passive)
- return state.dict[self.key]
- else:
- # Return a new, empty value
- return self.initialize(state)
+ # if no history, check for lazy callables, etc.
+ if self.key not in state.committed_state:
+ callable_ = self._get_callable(state)
+ if callable_ is not None:
+ if passive:
+ return PASSIVE_NORESULT
+ value = callable_()
+ if value is not ATTR_WAS_SET:
+ return self.set_committed_value(state, value)
+ else:
+ if self.key not in state.dict:
+ return self.get(state, passive=passive)
+ return state.dict[self.key]
+
+ # Return a new, empty value
+ return self.initialize(state)
def append(self, state, value, initiator, passive=False):
self.set(state, value, initiator)
@@ -767,9 +769,11 @@ class InstanceState(object):
self.dict.pop(attr.impl.key, None)
self.callables[attr.impl.key] = self.__fire_trigger
self.expired_attributes.add(attr.impl.key)
+ self.committed_state = {}
else:
for key in attribute_names:
self.dict.pop(key, None)
+ self.committed_state.pop(key, None)
if not getattr(self.class_, key).impl.accepts_global_callable:
continue
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index ddeaaf8ad..55001dc70 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -1398,9 +1398,8 @@ class ColumnElement(ClauseElement, _CompareMixin):
docstring for more details.
"""
- def __init__(self):
- self.primary_key = False
- self.foreign_keys = []
+ primary_key = False
+ foreign_keys = []
def base_columns(self):
if hasattr(self, '_base_columns'):
@@ -1557,7 +1556,6 @@ class FromClause(Selectable):
self.oid_column = None
def _get_from_objects(self, **modifiers):
- # this could also be [self], at the moment it doesnt matter to the Select object
return []
def default_order_by(self):
@@ -2486,7 +2484,6 @@ class _ColumnElementAdapter(ColumnElement):
"""
def __init__(self, elem):
- ColumnElement.__init__(self)
self.elem = elem
self.type = getattr(elem, 'type', None)
@@ -2900,8 +2897,11 @@ class _ScalarSelect(_Grouping):
__visit_name__ = 'grouping'
def __init__(self, elem):
- super(_ScalarSelect, self).__init__(elem)
- self.type = list(elem.inner_columns)[0].type
+ self.elem = elem
+ cols = list(elem.inner_columns)
+ if len(cols) != 1:
+ raise exceptions.InvalidRequestError("Scalar select can only be created from a Select object that has exactly one column expression.")
+ self.type = cols[0].type
def _no_cols(self):
raise exceptions.InvalidRequestError("Scalar Select expression has no columns; use this object directly within a column-level expression.")
@@ -3086,6 +3086,10 @@ class Select(_SelectBaseMixin, FromClause):
froms = property(_get_display_froms, doc="""Return a list of all FromClause elements which will be applied to the FROM clause of the resulting statement.""")
+ def type(self):
+ raise exceptions.InvalidRequestError("Select objects don't have a type. Call as_scalar() on this Select object to return a 'scalar' version of this Select.")
+ type = property(type)
+
def locate_all_froms(self):
"""return a Set of all FromClause elements referenced by this Select.