from SelectResults isn't present anymore, need to use join().
- postgres
- Added PGArray datatype for using postgres array datatypes
-
+
+0.3.11
+- orm
+ - added a check for joining from A->B using join(), along two
+ different m2m tables. this raises an error in 0.3 but is
+ possible in 0.4 when aliases are used. [ticket:687]
+- mssql
+ - added support for TIME columns (simulated using DATETIME) [ticket:679]
+ - index names are now quoted when dropping from reflected tables [ticket:684]
+
0.3.10
- general
- a new mutex that was added in 0.3.9 causes the pool_timeout
- postgres
- fixed max identifier length (63) [ticket:571]
-- mssql
- - added support for TIME columns (simulated using DATETIME) [ticket:679]
- - index names are now quoted when dropping from reflected tables [ticket:684]
0.3.9
- general
def visit_outer_join_column(self, vc):
return self.process(vc.column) + "(+)"
+
def uses_sequences_for_inserts(self):
return True
def clause_element(self):
return self.comparator.clause_element()
+
+ def expression_element(self):
+ return self.comparator.expression_element()
def operate(self, op, other, **kwargs):
return op(self.comparator, other, **kwargs)
class PropComparator(sql.ColumnOperators):
"""defines comparison operations for MapperProperty objects"""
-
+
+ def expression_element(self):
+ return self.clause_element()
+
def contains_op(a, b):
return a.contains(b)
contains_op = staticmethod(contains_op)
currenttables.append(join.left)
currenttables.append(join.right)
FindJoinedTables().traverse(clause)
-
mapper = start
alias = self._aliases
clause = clause.join(alias.alias, alias.primaryjoin, isouter=outerjoin)
else:
clause = clause.join(prop.select_table, prop.get_join(mapper), isouter=outerjoin)
+ elif not create_aliases and prop.secondary is not None and prop.secondary not in currenttables:
+ # TODO: this check is not strong enough for different paths to the same endpoint which
+ # does not use secondary tables
+ raise exceptions.InvalidRequestError("Can't join to property '%s'; a path to this table along a different secondary table already exists. Use the `alias=True` argument to `join()`." % prop.key)
+
mapper = prop.mapper
if create_aliases:
else:
return _BindParamClause(key, value, type_=type_, shortname=shortname, unique=unique)
+def outparam(key, type_=None):
+ """create an 'OUT' parameter for usage in functions (stored procedures), for databases
+ whith support them.
+
+ The ``outparam`` can be used like a regular function parameter. The "output" value will
+ be available from the [sqlalchemy.engine#ResultProxy] object via its ``out_parameters``
+ attribute, which returns a dictionary containing the values.
+ """
+
+ return _BindParamClause(key, type_=type_, unique=False, isoutparam=True)
+
def text(text, bind=None, *args, **kwargs):
"""Create literal text to be inserted into a query.
def _literal_as_text(element):
if isinstance(element, Operators):
- return element.clause_element()
+ return element.expression_element()
elif _is_literal(element):
return _TextClause(unicode(element))
else:
def _literal_as_binds(element, name='literal', type_=None):
if isinstance(element, Operators):
- return element.clause_element()
+ return element.expression_element()
elif _is_literal(element):
if element is None:
return null()
def _check_literal(self, other):
if isinstance(other, Operators):
- return other.clause_element()
+ return other.expression_element()
elif _is_literal(other):
return self._bind_param(other)
else:
def clause_element(self):
"""Allow ``_CompareMixins`` to return the underlying ``ClauseElement``, for non-``ClauseElement`` ``_CompareMixins``."""
-
return self
def expression_element(self):
__visit_name__ = 'bindparam'
- def __init__(self, key, value, shortname=None, type_=None, unique=False):
+ def __init__(self, key, value, shortname=None, type_=None, unique=False, isoutparam=False):
"""Construct a _BindParamClause.
key
modified if another ``_BindParamClause`` of the same
name already has been located within the containing
``ClauseElement``.
+
+ isoutparam
+ if True, the parameter should be treated like a stored procedure "OUT"
+ parameter.
"""
self.key = key or "{ANON %d param}" % id(self)
self.value = value
self.shortname = shortname or key
self.unique = unique
+ self.isoutparam = isoutparam
type_ = sqltypes.to_instance(type_)
if isinstance(type_, sqltypes.NullType) and type(value) in _BindParamClause.type_map:
self.type = sqltypes.to_instance(_BindParamClause.type_map[type(value)])
except exceptions.InvalidRequestError, e:
assert str(e) == "Ambiguous join for entity 'Mapper|Order|orders'; specify id=<someid> to query.join()/query.add_entity()"
+class MultiplePathTest(ORMTest):
+ def define_tables(self, metadata):
+ global t1, t2, t1t2_1, t1t2_2
+ t1 = Table('t1', metadata,
+ Column('id', Integer, primary_key=True),
+ Column('data', String(30))
+ )
+ t2 = Table('t2', metadata,
+ Column('id', Integer, primary_key=True),
+ Column('data', String(30))
+ )
+
+ t1t2_1 = Table('t1t2_1', metadata,
+ Column('t1id', Integer, ForeignKey('t1.id')),
+ Column('t2id', Integer, ForeignKey('t2.id'))
+ )
+
+ t1t2_2 = Table('t1t2_2', metadata,
+ Column('t1id', Integer, ForeignKey('t1.id')),
+ Column('t2id', Integer, ForeignKey('t2.id'))
+ )
+
+ def test_basic(self):
+ class T1(object):pass
+ class T2(object):pass
+
+ mapper(T1, t1, properties={
+ 't2s_1':relation(T2, secondary=t1t2_1),
+ 't2s_2':relation(T2, secondary=t1t2_2),
+ })
+ mapper(T2, t2)
+
+ try:
+ create_session().query(T1).join('t2s_1').filter(t2.c.id==5).reset_joinpoint().join('t2s_2')
+ assert False
+ except exceptions.InvalidRequestError, e:
+ assert str(e) == "Can't join to property 't2s_2'; a path to this table along a different secondary table already exists. Use the `alias=True` argument to `join()`."
+
+ create_session().query(T1).join('t2s_1', aliased=True).filter(t2.c.id==5).reset_joinpoint().join('t2s_2').all()
+ create_session().query(T1).join('t2s_1').filter(t2.c.id==5).reset_joinpoint().join('t2s_2', aliased=True).all()
+
+
+
class SynonymTest(QueryTest):
keep_mappers = True
keep_data = True