From 750439ac5fc61f03a09226db5d82b36c8b86739e Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 7 Nov 2007 22:25:01 +0000 Subject: [PATCH] - fixed remainder of [ticket:853] - bindparam 'shortname' is deprecated - fixed testing.assert_compile() to actually generate bind param dict before asserting - added bind param assertions to CRUDTest.test_update --- CHANGES | 3 +++ lib/sqlalchemy/orm/strategies.py | 4 ++-- lib/sqlalchemy/sql/compiler.py | 3 --- lib/sqlalchemy/sql/expression.py | 34 +++++++++++++------------------- test/orm/relationships.py | 23 ++++++++++++++------- test/sql/select.py | 5 +++-- test/testlib/testing.py | 2 +- 7 files changed, 39 insertions(+), 35 deletions(-) diff --git a/CHANGES b/CHANGES index 3ae068bc49..e29a5c5612 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,9 @@ CHANGES - sql + - the "shortname" keyword parameter on bindparam() has been + deprecated. + - Added contains operator (generates a "LIKE %%" clause). - Removed regular expression step from most statement compilations. diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index aea1ffdda6..d517be007e 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -433,7 +433,7 @@ class LazyLoader(AbstractRelationLoader): if should_bind(leftcol, rightcol): col = leftcol binary.left = binds.setdefault(leftcol, - sql.bindparam(None, None, shortname=leftcol.name, type_=binary.right.type, unique=True)) + sql.bindparam(None, None, type_=binary.right.type, unique=True)) reverse[rightcol] = binds[col] # the "left is not right" compare is to handle part of a join clause that is "table.c.col1==table.c.col1", @@ -441,7 +441,7 @@ class LazyLoader(AbstractRelationLoader): if leftcol is not rightcol and should_bind(rightcol, leftcol): col = rightcol binary.right = binds.setdefault(rightcol, - sql.bindparam(None, None, shortname=rightcol.name, type_=binary.left.type, unique=True)) + sql.bindparam(None, None, type_=binary.left.type, unique=True)) reverse[leftcol] = binds[col] lazywhere = primaryjoin diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index ba48422785..9c82cd4aa6 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -362,9 +362,6 @@ class DefaultCompiler(engine.Compiled): def visit_bindparam(self, bindparam, **kwargs): # apply truncation to the ultimate generated name - if bindparam.shortname != bindparam.key: - self.binds.setdefault(bindparam.shortname, bindparam) - if bindparam.unique: count = 1 key = bindparam.key diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 75c809004f..479ce64253 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -666,22 +666,20 @@ def table(name, *columns): return TableClause(name, *columns) -def bindparam(key, value=None, type_=None, shortname=None, unique=False): +def bindparam(key, value=None, shortname=None, type_=None, unique=False): """Create a bind parameter clause with the given key. value a default value for this bind parameter. a bindparam with a value is called a ``value-based bindparam``. - shortname - an ``alias`` for this bind parameter. usually used to alias the - ``key`` nd ``label`` of a column, i.e. ``somecolname`` and - ``sometable_somecolname`` - type a sqlalchemy.types.TypeEngine object indicating the type of this bind param, will invoke type-specific bind parameter processing + shortname + deprecated. + unique if True, bind params sharing the same name will have their underlying ``key`` modified to a uniquely generated name. @@ -689,9 +687,9 @@ def bindparam(key, value=None, type_=None, shortname=None, unique=False): """ if isinstance(key, _ColumnClause): - return _BindParamClause(key.name, value, type_=key.type, shortname=shortname, unique=unique) + return _BindParamClause(key.name, value, type_=key.type, unique=unique, shortname=shortname) else: - return _BindParamClause(key, value, type_=type_, shortname=shortname, unique=unique) + return _BindParamClause(key, value, type_=type_, unique=unique, shortname=shortname) def outparam(key, type_=None): """Create an 'OUT' parameter for usage in functions (stored procedures), for databases which support them. @@ -807,7 +805,7 @@ def _literal_as_binds(element, name='literal', type_=None): if element is None: return null() else: - return _BindParamClause(name, element, shortname=name, type_=type_, unique=True) + return _BindParamClause(name, element, type_=type_, unique=True) else: return element @@ -1325,7 +1323,7 @@ class _CompareMixin(ColumnOperators): return lambda other: self.__operate(operator, other) def _bind_param(self, obj): - return _BindParamClause('literal', obj, shortname=None, type_=self.type, unique=True) + return _BindParamClause('literal', obj, type_=self.type, unique=True) def _check_literal(self, other): if isinstance(other, Operators): @@ -1706,7 +1704,7 @@ class _BindParamClause(ClauseElement, _CompareMixin): __visit_name__ = 'bindparam' - def __init__(self, key, value, shortname=None, type_=None, unique=False, isoutparam=False): + def __init__(self, key, value, type_=None, unique=False, isoutparam=False, shortname=None): """Construct a _BindParamClause. key @@ -1723,12 +1721,8 @@ class _BindParamClause(ClauseElement, _CompareMixin): compilation/execution. shortname - Defaults to the key, a *short name* that will also identify - this bind parameter, similar to an alias. the bind - parameter keys sent to a statement compilation or compiled - execution may match either the key or the shortname of the - corresponding ``_BindParamClause`` objects. - + deprecated. + type\_ A ``TypeEngine`` object that will be used to pre-process the value corresponding to this ``_BindParamClause`` at @@ -1747,10 +1741,10 @@ class _BindParamClause(ClauseElement, _CompareMixin): self.key = key or "{ANON %d param}" % id(self) self.value = value - self.shortname = shortname or key self.unique = unique self.isoutparam = isoutparam - + self.shortname = shortname + if type_ is None: self.type = self.type_map.get(type(value), sqltypes.NullType)() elif isinstance(type_, type): @@ -2607,7 +2601,7 @@ class _ColumnClause(ColumnElement): return [] def _bind_param(self, obj): - return _BindParamClause(self._label, obj, shortname=self.name, type_=self.type, unique=True) + return _BindParamClause(self._label, obj, type_=self.type, unique=True) def _make_proxy(self, selectable, name = None): # propigate the "is_literal" flag only if we are keeping our name, diff --git a/test/orm/relationships.py b/test/orm/relationships.py index 282d1cafc0..0af70975ab 100644 --- a/test/orm/relationships.py +++ b/test/orm/relationships.py @@ -401,7 +401,7 @@ class RelationTest4(ORMTest): except exceptions.AssertionError, e: assert str(e).startswith("Dependency rule tried to blank-out primary key column 'B.id' on instance ") - def test_no_nullPK_sBtoA(self): + def test_no_nullPK_BtoA(self): class A(object):pass class B(object):pass mapper(B, tableB, properties={ @@ -421,17 +421,26 @@ class RelationTest4(ORMTest): except exceptions.AssertionError, e: assert str(e).startswith("Dependency rule tried to blank-out primary key column 'B.id' on instance ") - def test_nullPKsOK_sBtoA(self): + @testing.supported('sqlite', 'mysql') + def test_nullPKsOK_BtoA(self): + # postgres cant handle a nullable PK column...? + tableC = Table('tablec', tableA.metadata, + Column('id', Integer, primary_key=True), + Column('a_id', Integer, ForeignKey('A.id'), primary_key=True, autoincrement=False, nullable=True)) + tableC.create() + class A(object):pass - class B(object):pass - mapper(B, tableB, properties={ + class C(object):pass + mapper(C, tableC, properties={ 'a':relation(A, cascade="save-update") }, allow_null_pks=True) mapper(A, tableA) - b1 = B() - b1.a = None + c1 = C() + c1.id = 5 + c1.a = None sess = create_session() - sess.save(b1) + sess.save(c1) + # test that no error is raised. sess.flush() def test_delete_cascade_BtoA(self): diff --git a/test/sql/select.py b/test/sql/select.py index 1999b52a07..678085fc18 100644 --- a/test/sql/select.py +++ b/test/sql/select.py @@ -1175,9 +1175,10 @@ class CRUDTest(SQLCompileTest): self.assert_compile(update(table1, table1.c.myid == 7), "UPDATE mytable SET name=:name WHERE mytable.myid = :mytable_myid", params = {table1.c.name:'fred'}) self.assert_compile(update(table1, table1.c.myid == 7), "UPDATE mytable SET name=:name WHERE mytable.myid = :mytable_myid", params = {'name':'fred'}) self.assert_compile(update(table1, values = {table1.c.name : table1.c.myid}), "UPDATE mytable SET name=mytable.myid") - self.assert_compile(update(table1, whereclause = table1.c.name == bindparam('crit'), values = {table1.c.name : 'hi'}), "UPDATE mytable SET name=:name WHERE mytable.name = :crit", params = {'crit' : 'notthere'}) - self.assert_compile(update(table1, table1.c.myid == 12, values = {table1.c.name : table1.c.myid}), "UPDATE mytable SET name=mytable.myid, description=:description WHERE mytable.myid = :mytable_myid", params = {'description':'test'}) + self.assert_compile(update(table1, whereclause = table1.c.name == bindparam('crit'), values = {table1.c.name : 'hi'}), "UPDATE mytable SET name=:name WHERE mytable.name = :crit", params = {'crit' : 'notthere'}, checkparams={'crit':'notthere', 'name':'hi'}) + self.assert_compile(update(table1, table1.c.myid == 12, values = {table1.c.name : table1.c.myid}), "UPDATE mytable SET name=mytable.myid, description=:description WHERE mytable.myid = :mytable_myid", params = {'description':'test'}, checkparams={'description':'test', 'mytable_myid':12}) self.assert_compile(update(table1, table1.c.myid == 12, values = {table1.c.myid : 9}), "UPDATE mytable SET myid=:myid, description=:description WHERE mytable.myid = :mytable_myid", params = {'mytable_myid': 12, 'myid': 9, 'description': 'test'}) + self.assert_compile(update(table1, table1.c.myid ==12), "UPDATE mytable SET myid=:myid WHERE mytable.myid = :mytable_myid", params={'myid':18}, checkparams={'myid':18, 'mytable_myid':12}) s = table1.update(table1.c.myid == 12, values = {table1.c.name : 'lala'}) c = s.compile(column_keys=['mytable_id', 'name']) self.assert_compile(update(table1, table1.c.myid == 12, values = {table1.c.name : table1.c.myid}).values({table1.c.name:table1.c.name + 'foo'}), "UPDATE mytable SET name=(mytable.name || :mytable_name), description=:description WHERE mytable.myid = :mytable_myid", params = {'description':'test'}) diff --git a/test/testlib/testing.py b/test/testlib/testing.py index 6342ce898d..95071a4751 100644 --- a/test/testlib/testing.py +++ b/test/testlib/testing.py @@ -295,7 +295,7 @@ class SQLCompileTest(PersistTest): self.assert_(cc == result, "\n'" + cc + "'\n does not match \n'" + result + "'") if checkparams is not None: - self.assert_(c.params == checkparams, "params dont match" + repr(c.params)) + self.assert_(c.construct_params(params) == checkparams, "params dont match" + repr(c.params)) class AssertMixin(PersistTest): """given a list-based structure of keys/properties which represent information within an object structure, and -- 2.47.2