:released: Fri Apr 04 2008
.. change::
:tags: orm
:tickets:
A small change in behavior to session.merge() - existing
objects are checked for based on primary key attributes, not
necessarily _instance_key. So the widely requested
capability, that:
x = MyObject(id=1)
x = sess.merge(x)
will in fact load MyObject with id 1 from the database if
present, is now available. merge() still copies the state
of the given object to the persistent one, so an example
like the above would typically have copied "None" from all
attributes of "x" onto the persistent copy. These can be
reverted using session.expire(x).
.. change::
:tags: orm
:tickets:
Also fixed behavior in merge() whereby collection elements
present on the destination but not the merged collection
were not being removed from the destination.
.. change::
:tags: orm
:tickets: 995
Added a more aggressive check for "uncompiled mappers",
helps particularly with declarative layer
.. change::
:tags: orm
:tickets:
The methodology behind "primaryjoin"/"secondaryjoin" has
been refactored. Behavior should be slightly more
intelligent, primarily in terms of error messages which
have been pared down to be more readable. In a slight
number of scenarios it can better resolve the correct
foreign key than before.
.. change::
:tags: orm
:tickets:
Added comparable_property(), adds query Comparator
behavior to regular, unmanaged Python properties
.. change::
:tags: orm, Company.employees.of_type(Engineer), 'machines'
:tickets:
the functionality of query.with_polymorphic() has
been added to mapper() as a configuration option.
It's set via several forms:
with_polymorphic='*'
with_polymorphic=[mappers]
with_polymorphic=('*', selectable)
with_polymorphic=([mappers], selectable)
This controls the default polymorphic loading strategy
for inherited mappers. When a selectable is not given,
outer joins are created for all joined-table inheriting
mappers requested. Note that the auto-create of joins
is not compatible with concrete table inheritance.
The existing select_table flag on mapper() is now
deprecated and is synonymous with
with_polymorphic('*', select_table). Note that the
underlying "guts" of select_table have been
completely removed and replaced with the newer,
more flexible approach.
The new approach also automatically allows eager loads
to work for subclasses, if they are present, for
example::
sess.query(Company).options(eagerload_all())
to load Company objects, their employees, and the
'machines' collection of employees who happen to be
Engineers. A "with_polymorphic" Query option should be
introduced soon as well which would allow per-Query
control of with_polymorphic() on relations.
.. change::
:tags: orm
:tickets:
added two "experimental" features to Query,
"experimental" in that their specific name/behavior
is not carved in stone just yet: _values() and
_from_self(). We'd like feedback on these.
- _values(\*columns) is given a list of column
expressions, and returns a new Query that only
returns those columns. When evaluated, the return
value is a list of tuples just like when using
add_column() or add_entity(), the only difference is
that "entity zero", i.e. the mapped class, is not
included in the results. This means it finally makes
sense to use group_by() and having() on Query, which
have been sitting around uselessly until now.
A future change to this method may include that its
ability to join, filter and allow other options not
related to a "resultset" are removed, so the feedback
we're looking for is how people want to use
_values()...i.e. at the very end, or do people prefer
to continue generating after it's called.
- _from_self() compiles the SELECT statement for the
Query (minus any eager loaders), and returns a new
Query that selects from that SELECT. So basically you
can query from a Query without needing to extract the
SELECT statement manually. This gives meaning to
operations like query[3:5]._from_self().filter(some
criterion). There's not much controversial here
except that you can quickly create highly nested
queries that are less efficient, and we want feedback
on the naming choice.
.. change::
:tags: orm
:tickets:
query.order_by() and query.group_by() will accept
multiple arguments using \*args (like select()
already does).
.. change::
:tags: orm
:tickets:
Added some convenience descriptors to Query:
query.statement returns the full SELECT construct,
query.whereclause returns just the WHERE part of the
SELECT construct.
.. change::
:tags: orm
:tickets:
Fixed/covered case when using a False/0 value as a
polymorphic discriminator.
.. change::
:tags: orm
:tickets:
Fixed bug which was preventing synonym() attributes from
being used with inheritance
.. change::
:tags: orm
:tickets: 996
Fixed SQL function truncation of trailing underscores
.. change::
:tags: orm
:tickets:
When attributes are expired on a pending instance, an
error will not be raised when the "refresh" action is
triggered and no result is found.
.. change::
:tags: orm
:tickets:
Session.execute can now find binds from metadata
.. change::
:tags: orm
:tickets:
Adjusted the definition of "self-referential" to be any
two mappers with a common parent (this affects whether or
not aliased=True is required when joining with Query).
.. change::
:tags: orm
:tickets:
Made some fixes to the "from_joinpoint" argument to
query.join() so that if the previous join was aliased and
this one isn't, the join still happens successfully.
.. change::
:tags: orm
:tickets: 895
Assorted "cascade deletes" fixes:
- Fixed "cascade delete" operation of dynamic relations,
which had only been implemented for foreign-key
nulling behavior in 0.4.2 and not actual cascading
deletes
- Delete cascade without delete-orphan cascade on a
many-to-one will not delete orphans which were
disconnected from the parent before session.delete()
is called on the parent (one-to-many already had
this).
- Delete cascade with delete-orphan will delete orphans
whether or not it remains attached to its also-deleted
parent.
- delete-orphan cascade is properly detected on relations
that are present on superclasses when using inheritance.
.. change::
:tags: orm
:tickets:
Fixed order_by calculation in Query to properly alias
mapper-config'ed order_by when using select_from()
.. change::
:tags: orm
:tickets:
Refactored the diffing logic that kicks in when replacing
one collection with another into collections.bulk_replace,
useful to anyone building multi-level collections.
.. change::
:tags: orm
:tickets:
Cascade traversal algorithm converted from recursive to
iterative to support deep object graphs.
.. change::
:tags: sql
:tickets: 999
schema-qualified tables now will place the schemaname
ahead of the tablename in all column expressions as well
as when generating column labels. This prevents cross-
schema name collisions in all cases
.. change::
:tags: sql
:tickets:
can now allow selects which correlate all FROM clauses
and have no FROM themselves. These are typically
used in a scalar context, i.e. SELECT x, (SELECT x WHERE y)
FROM table. Requires explicit correlate() call.
.. change::
:tags: sql
:tickets:
'name' is no longer a required constructor argument for
Column(). It (and .key) may now be deferred until the
column is added to a Table.
.. change::
:tags: sql
:tickets: 791, 993
like(), ilike(), contains(), startswith(), endswith() take
an optional keyword argument "escape=<somestring>", which
is set as the escape character using the syntax "x LIKE y
ESCAPE '<somestring>'".
.. change::
:tags: sql
:tickets:
random() is now a generic sql function and will compile to
the database's random implementation, if any.
.. change::
:tags: sql
:tickets:
update().values() and insert().values() take keyword
arguments.
.. change::
:tags: sql
:tickets:
Fixed an issue in select() regarding its generation of
FROM clauses, in rare circumstances two clauses could be
produced when one was intended to cancel out the other.
Some ORM queries with lots of eager loads might have seen
this symptom.
.. change::
:tags: sql
:tickets:
The case() function now also takes a dictionary as its
whens parameter. It also interprets the "THEN"
expressions as values by default, meaning case([(x==y,
"foo")]) will interpret "foo" as a bound value, not a SQL
expression. use text(expr) for literal SQL expressions in
this case. For the criterion itself, these may be literal
strings only if the "value" keyword is present, otherwise
SA will force explicit usage of either text() or
literal().
.. change::
:tags: oracle
:tickets:
The "owner" keyword on Table is now deprecated, and is
exactly synonymous with the "schema" keyword. Tables can
now be reflected with alternate "owner" attributes,
explicitly stated on the Table object or not using
"schema".
.. change::
:tags: oracle
:tickets:
All of the "magic" searching for synonyms, DBLINKs etc.
during table reflection are disabled by default unless you
specify "oracle_resolve_synonyms=True" on the Table
object. Resolving synonyms necessarily leads to some
messy guessing which we'd rather leave off by default.
When the flag is set, tables and related tables will be
resolved against synonyms in all cases, meaning if a
synonym exists for a particular table, reflection will use
it when reflecting related tables. This is stickier
behavior than before which is why it's off by default.
.. change::
:tags: declarative, extension
:tickets:
The "synonym" function is now directly usable with
"declarative". Pass in the decorated property using the
"descriptor" keyword argument, e.g.: somekey =
synonym('_somekey', descriptor=property(g, s))
.. change::
:tags: declarative, extension
:tickets:
The "deferred" function is usable with "declarative".
Simplest usage is to declare deferred and Column together,
e.g.: data = deferred(Column(Text))
.. change::
:tags: declarative, extension
:tickets:
Declarative also gained synonym_for(...) and
comparable_using(...), front-ends for synonym and
comparable_property.
.. change::
:tags: declarative, extension
:tickets: 995
Improvements to mapper compilation when using declarative;
already-compiled mappers will still trigger compiles of
other uncompiled mappers when used
.. change::
:tags: declarative, extension
:tickets:
Declarative will complete setup for Columns lacking names,
allows a more DRY syntax.
class Foo(Base):
__tablename__ = 'foos'
id = Column(Integer, primary_key=True)
.. change::
:tags: declarative, extension
:tickets:
inheritance in declarative can be disabled when sending
"inherits=None" to __mapper_args__.
.. change::
:tags: declarative, extension
:tickets:
declarative_base() takes optional kwarg "mapper", which
is any callable/class/method that produces a mapper,
such as declarative_base(mapper=scopedsession.mapper).
This property can also be set on individual declarative
classes using the "__mapper_cls__" property.
.. change::
:tags: postgres
:tickets: 1001
Got PG server side cursors back into shape, added fixed
unit tests as part of the default test suite. Added
better uniqueness to the cursor ID
.. change::
:tags: oracle
:tickets:
The "owner" keyword on Table is now deprecated, and is
exactly synonymous with the "schema" keyword. Tables can
now be reflected with alternate "owner" attributes,
explicitly stated on the Table object or not using
"schema".
.. change::
:tags: oracle
:tickets:
All of the "magic" searching for synonyms, DBLINKs etc.
during table reflection are disabled by default unless you
specify "oracle_resolve_synonyms=True" on the Table
object. Resolving synonyms necessarily leads to some
messy guessing which we'd rather leave off by default.
When the flag is set, tables and related tables will be
resolved against synonyms in all cases, meaning if a
synonym exists for a particular table, reflection will use
it when reflecting related tables. This is stickier
behavior than before which is why it's off by default.
.. change::
:tags: mssql
:tickets: 979
Reflected tables will now automatically load other tables
which are referenced by Foreign keys in the auto-loaded
table,.
.. change::
:tags: mssql
:tickets: 916
Added executemany check to skip identity fetch,.
.. change::
:tags: mssql
:tickets: 884
Added stubs for small date type.
.. change::
:tags: mssql
:tickets:
Added a new 'driver' keyword parameter for the pyodbc dialect.
Will substitute into the ODBC connection string if given,
defaults to 'SQL Server'.
.. change::
:tags: mssql
:tickets:
Added a new 'max_identifier_length' keyword parameter for
the pyodbc dialect.
.. change::
:tags: mssql
:tickets:
Improvements to pyodbc + Unix. If you couldn't get that
combination to work before, please try again.
.. change::
:tags: mysql
:tickets:
The connection.info keys the dialect uses to cache server
settings have changed and are now namespaced.
.. changelog::