Thread: [Sqlalchemy-commits] sqlalchemy: Add special containment operation methods for PG arr...
Brought to you by:
zzzeek
From: <co...@sq...> - 2012-11-24 15:49:35
|
details: http://hg.sqlalchemy.org/sqlalchemy/sqlalchemy/rev/4abbe7679dc0 changeset: 8962:4abbe7679dc0 user: Audrius Ka?ukauskas <au...@ne...> date: Tue Nov 20 23:24:34 2012 +0200 description: Add special containment operation methods for PG array type Subject: sqlalchemy: HSTORE.comparator_factory should subclass Concatenable.Comparator details: http://hg.sqlalchemy.org/sqlalchemy/sqlalchemy/rev/8e6fb383adcd changeset: 8963:8e6fb383adcd user: Audrius Ka?ukauskas <au...@ne...> date: Wed Nov 21 00:26:20 2012 +0200 description: HSTORE.comparator_factory should subclass Concatenable.Comparator Subject: sqlalchemy: merge Audrius HSTORE commits from bitbucket details: http://hg.sqlalchemy.org/sqlalchemy/sqlalchemy/rev/a55d5f39f123 changeset: 8964:a55d5f39f123 user: Mike Bayer <mi...@zz...> date: Sat Nov 24 10:49:14 2012 -0500 description: merge Audrius HSTORE commits from bitbucket diffstat: doc/build/changelog/changelog_08.rst | 40 + doc/build/dialects/postgresql.rst | 2 +- lib/sqlalchemy/dialects/drizzle/base.py | 10 - lib/sqlalchemy/dialects/firebird/base.py | 8 +- lib/sqlalchemy/dialects/informix/base.py | 18 - lib/sqlalchemy/dialects/mysql/base.py | 8 +- lib/sqlalchemy/dialects/postgresql/base.py | 42 +- lib/sqlalchemy/dialects/postgresql/hstore.py | 13 +- lib/sqlalchemy/engine/base.py | 5 +- lib/sqlalchemy/engine/default.py | 23 +- lib/sqlalchemy/engine/interfaces.py | 126 ++++- lib/sqlalchemy/events.py | 52 ++- lib/sqlalchemy/orm/__init__.py | 7 +- lib/sqlalchemy/pool.py | 76 ++- test/dialect/test_postgresql.py | 87 +++- test/engine/test_pool.py | 78 +++- test/profiles.txt | 10 +- test/sql/test_labels.py | 348 +++++++++------ test/sql/test_quote.py | 602 +++++++++++++++++++++----- 19 files changed, 1150 insertions(+), 405 deletions(-) diffs (truncated from 2312 to 300 lines): diff -r b91c1cc4c893 -r a55d5f39f123 doc/build/changelog/changelog_08.rst --- a/doc/build/changelog/changelog_08.rst Tue Nov 20 11:03:01 2012 -0500 +++ b/doc/build/changelog/changelog_08.rst Sat Nov 24 10:49:14 2012 -0500 @@ -114,6 +114,46 @@ Support for reflection of the "name" of primary key constraints added, courtesy Dave Moore. + .. change:: + :tags: informix + + Some cruft regarding informix transaction handling has been + removed, including a feature that would skip calling + commit()/rollback() as well as some hardcoded isolation level + assumptions on begin().. The status of this dialect is not + well understood as we don't have any users working with it, + nor any access to an Informix database. If someone with + access to Informix wants to help test this dialect, please + let us know. + + .. change:: + :tags: pool, feature + + The :class:`.Pool` will now log all connection.close() + operations equally, including closes which occur for + invalidated connections, detached connections, and connections + beyond the pool capacity. + + .. change:: + :tags: pool, feature + :tickets: 2611 + + The :class:`.Pool` now consults the :class:`.Dialect` for + functionality regarding how the connection should be + "auto rolled back", as well as closed. This grants more + control of transaction scope to the dialect, so that we + will be better able to implement transactional workarounds + like those potentially needed for pysqlite and cx_oracle. + + .. change:: + :tags: pool, feature + + Added new :meth:`.PoolEvents.reset` hook to capture + the event before a connection is auto-rolled back, upon + return to the pool. Together with + :meth:`.ConnectionEvents.rollback` this allows all rollback + events to be intercepted. + .. changelog:: :version: 0.8.0b1 :released: October 30, 2012 diff -r b91c1cc4c893 -r a55d5f39f123 doc/build/dialects/postgresql.rst --- a/doc/build/dialects/postgresql.rst Tue Nov 20 11:03:01 2012 -0500 +++ b/doc/build/dialects/postgresql.rst Sat Nov 24 10:49:14 2012 -0500 @@ -26,7 +26,7 @@ .. autoclass:: array .. autoclass:: ARRAY - :members: __init__ + :members: __init__, Comparator :show-inheritance: .. autoclass:: BIT diff -r b91c1cc4c893 -r a55d5f39f123 lib/sqlalchemy/dialects/drizzle/base.py --- a/lib/sqlalchemy/dialects/drizzle/base.py Tue Nov 20 11:03:01 2012 -0500 +++ b/lib/sqlalchemy/dialects/drizzle/base.py Sat Nov 24 10:49:14 2012 -0500 @@ -446,16 +446,6 @@ conn.autocommit(False) return connect - def do_commit(self, connection): - """Execute a COMMIT.""" - - connection.commit() - - def do_rollback(self, connection): - """Execute a ROLLBACK.""" - - connection.rollback() - @reflection.cache def get_table_names(self, connection, schema=None, **kw): """Return a Unicode SHOW TABLES from a given schema.""" diff -r b91c1cc4c893 -r a55d5f39f123 lib/sqlalchemy/dialects/firebird/base.py --- a/lib/sqlalchemy/dialects/firebird/base.py Tue Nov 20 11:03:01 2012 -0500 +++ b/lib/sqlalchemy/dialects/firebird/base.py Sat Nov 24 10:49:14 2012 -0500 @@ -723,10 +723,10 @@ # when there are no arguments. cursor.execute(statement, parameters or []) - def do_rollback(self, connection): + def do_rollback(self, dbapi_connection): # Use the retaining feature, that keeps the transaction going - connection.rollback(True) + dbapi_connection.rollback(True) - def do_commit(self, connection): + def do_commit(self, dbapi_connection): # Use the retaining feature, that keeps the transaction going - connection.commit(True) + dbapi_connection.commit(True) diff -r b91c1cc4c893 -r a55d5f39f123 lib/sqlalchemy/dialects/informix/base.py --- a/lib/sqlalchemy/dialects/informix/base.py Tue Nov 20 11:03:01 2012 -0500 +++ b/lib/sqlalchemy/dialects/informix/base.py Sat Nov 24 10:49:14 2012 -0500 @@ -362,10 +362,6 @@ preparer = InformixIdentifierPreparer default_paramstyle = 'qmark' - def __init__(self, has_transactions=True, *args, **kwargs): - self.has_transactions = has_transactions - default.DefaultDialect.__init__(self, *args, **kwargs) - def initialize(self, connection): super(InformixDialect, self).initialize(connection) @@ -375,20 +371,6 @@ else: self.max_identifier_length = 128 - def do_begin(self, connection): - cu = connection.cursor() - cu.execute('SET LOCK MODE TO WAIT') - if self.has_transactions: - cu.execute('SET ISOLATION TO REPEATABLE READ') - - def do_commit(self, connection): - if self.has_transactions: - connection.commit() - - def do_rollback(self, connection): - if self.has_transactions: - connection.rollback() - def _get_table_names(self, connection, schema, type, **kw): schema = schema or self.default_schema_name s = "select tabname, owner from systables where owner=? and tabtype=?" diff -r b91c1cc4c893 -r a55d5f39f123 lib/sqlalchemy/dialects/mysql/base.py --- a/lib/sqlalchemy/dialects/mysql/base.py Tue Nov 20 11:03:01 2012 -0500 +++ b/lib/sqlalchemy/dialects/mysql/base.py Sat Nov 24 10:49:14 2012 -0500 @@ -1933,7 +1933,7 @@ cursor.close() return val.upper().replace("-", " ") - def do_commit(self, connection): + def do_commit(self, dbapi_connection): """Execute a COMMIT.""" # COMMIT/ROLLBACK were introduced in 3.23.15. @@ -1942,7 +1942,7 @@ # Ignore commit/rollback if support isn't present, otherwise even basic # operations via autocommit fail. try: - connection.commit() + dbapi_connection.commit() except: if self.server_version_info < (3, 23, 15): args = sys.exc_info()[1].args @@ -1950,11 +1950,11 @@ return raise - def do_rollback(self, connection): + def do_rollback(self, dbapi_connection): """Execute a ROLLBACK.""" try: - connection.rollback() + dbapi_connection.rollback() except: if self.server_version_info < (3, 23, 15): args = sys.exc_info()[1].args diff -r b91c1cc4c893 -r a55d5f39f123 lib/sqlalchemy/dialects/postgresql/base.py --- a/lib/sqlalchemy/dialects/postgresql/base.py Tue Nov 20 11:03:01 2012 -0500 +++ b/lib/sqlalchemy/dialects/postgresql/base.py Sat Nov 24 10:49:14 2012 -0500 @@ -464,12 +464,21 @@ as well as UPDATE statements when the :meth:`.Update.values` method is used:: - mytable.update().values({mytable.c.data[5]:7, - mytable.c.data[2:7]:[1,2,3]}) + mytable.update().values({ + mytable.c.data[5]: 7, + mytable.c.data[2:7]: [1, 2, 3] + }) + + :class:`.ARRAY` provides special methods for containment operations, + e.g.:: + + mytable.c.data.contains([1, 2]) + + For a full list of special methods see :class:`.ARRAY.Comparator`. .. versionadded:: 0.8 Added support for index and slice operations to the :class:`.ARRAY` type, including support for UPDATE - statements. + statements, and special array containment operations. The :class:`.ARRAY` type may not be supported on all DBAPIs. It is known to work on psycopg2 and not pg8000. @@ -482,6 +491,8 @@ __visit_name__ = 'ARRAY' class Comparator(sqltypes.Concatenable.Comparator): + """Define comparison operations for :class:`.ARRAY`.""" + def __getitem__(self, index): if isinstance(index, slice): index = _Slice(index, self) @@ -491,6 +502,31 @@ return self._binary_operate(self.expr, operators.getitem, index, result_type=return_type) + def contains(self, other, **kwargs): + """Boolean expression. Test if elements are a superset of the + elements of the argument array expression. + """ + return self.expr.op('@>')(other) + + def contained_by(self, other): + """Boolean expression. Test if elements are a proper subset of the + elements of the argument array expression. + """ + return self.expr.op('<@')(other) + + def overlap(self, other): + """Boolean expression. Test if array has elements in common with + an argument array expression. + """ + return self.expr.op('&&')(other) + + def _adapt_expression(self, op, other_comparator): + if isinstance(op, operators.custom_op): + if op.opstring in ['@>', '<@', '&&']: + return op, sqltypes.Boolean + return sqltypes.Concatenable.Comparator.\ + _adapt_expression(self, op, other_comparator) + comparator_factory = Comparator def __init__(self, item_type, as_tuple=False, dimensions=None): diff -r b91c1cc4c893 -r a55d5f39f123 lib/sqlalchemy/dialects/postgresql/hstore.py --- a/lib/sqlalchemy/dialects/postgresql/hstore.py Tue Nov 20 11:03:01 2012 -0500 +++ b/lib/sqlalchemy/dialects/postgresql/hstore.py Sat Nov 24 10:49:14 2012 -0500 @@ -47,7 +47,7 @@ residual = residual[:-1] + '[...]' return "After %r, could not parse residual at position %d: %r" % ( - parsed_tail, pos, residual) + parsed_tail, pos, residual) def _parse_hstore(hstore_str): @@ -173,7 +173,7 @@ __visit_name__ = 'HSTORE' - class comparator_factory(sqltypes.TypeEngine.Comparator): + class comparator_factory(sqltypes.Concatenable.Comparator): """Define comparison operations for :class:`.HSTORE`.""" def has_key(self, other): @@ -218,12 +218,6 @@ """ return self.expr.op('->', precedence=5)(other) - def __add__(self, other): - """HStore expression. Merge the left and right hstore expressions, - with duplicate keys taking the value from the right expression. - """ - return self.expr.concat(other) - def delete(self, key): """HStore expression. Returns the contents of this hstore with the given key deleted. Note that the key may be a SQLA expression. @@ -262,7 +256,8 @@ return op, sqltypes.Boolean elif op.opstring == '->': return op, sqltypes.Text - return op, other_comparator.type + return sqltypes.Concatenable.Comparator.\ + _adapt_expression(self, op, other_comparator) def bind_processor(self, dialect): def process(value): diff -r b91c1cc4c893 -r a55d5f39f123 lib/sqlalchemy/engine/base.py --- a/lib/sqlalchemy/engine/base.py Tue Nov 20 11:03:01 2012 -0500 +++ b/lib/sqlalchemy/engine/base.py Sat Nov 24 10:49:14 2012 -0500 @@ -479,7 +479,7 @@ else: self.__transaction = None - def _commit_impl(self): + def _commit_impl(self, autocommit=False): if self._has_events: self.dispatch.commit(self) @@ -910,7 +910,7 @@ result.close(_autoclose_connection=False) if self.__transaction is None and context.should_autocommit: - self._commit_impl() |