Commit Graph

1791 Commits

Author SHA1 Message Date
Mike Bayer 09df554a85 honor NO_CACHE in lambdas
Fixed issue in lambda caching system where an element of a query that
produces no cache key, like a custom option or clause element, would still
populate the expression in the "lambda cache" inappropriately.

This was discovered as part of 🎫`6887` but is a separate
issue.

References: #6887
Change-Id: I1665f4320254ddc63a0abf3088e9daeaffbd1840
2021-08-17 14:30:24 -04:00
Mike Bayer b987465332 fix linter JOIN logic; fix PostgreSQL ARRAY op comparison
Adjusted the "from linter" warning feature to accommodate for a chain of
joins more than one level deep where the ON clauses don't explicitly match
up the targets, such as an expression such as "ON TRUE". This mode of use
is intended to cancel the cartesian product warning simply by the fact that
there's a JOIN from "a to b", which was not working for the case where the
chain of joins had more than one element.

this incurs a bit more compiler overhead that comes out in profiling
but is not extensive.

Added the "is_comparison" flag to the PostgreSQL "overlaps",
"contained_by", "contains" operators, so that they work in relevant ORM
contexts as well as in conjunction with the "from linter" feature.

Fixes: #6886
Change-Id: I078dc3fe6d4f7871ffe4ebac3e71e62f3f213d12
2021-08-15 23:14:59 -04:00
mike bayer 3866e931e8 Merge "Unify native and non-native valid values for `Enum`" 2021-08-13 15:44:24 +00:00
mike bayer cb8906bab1 Merge "add columns_clause_froms and related use cases" 2021-08-09 18:53:06 +00:00
mike bayer 5434e64b2f Merge "Dispatch independent ctes on compound select" 2021-08-08 16:38:48 +00:00
Eric Masseran 770d50092f Dispatch independent ctes on compound select
Fix issue in :class:`_sql.CTE` where new :meth:`_sql.HasCTE.add_cte` method
added in version 1.4.21 / 🎫`6752` failed to function correctly for
"compound select" structures such as :func:`_sql.union`,
:func:`_sql.union_all`, :func:`_sql.except`, etc. Pull request courtesy
Eric Masseran.

Fixes: #6752
Closes: #6849
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/6849
Pull-request-sha: 1c4b4d72b2

Change-Id: I49a16a4fc2af8299502011f3a02d8a2ad93255e3
2021-08-08 10:44:14 -04:00
mike bayer 9a01ea0777 Merge "dont qualify literal_binds with literal_execute" 2021-08-07 18:56:11 +00:00
Mike Bayer d49eef15bf add columns_clause_froms and related use cases
Added new attribute :attr:`_sql.Select.columns_clause_froms` that will
retrieve the FROM list implied by the columns clause of the
:class:`_sql.Select` statement. This differs from the old
:attr:`_sql.Select.froms` collection in that it does not perform any ORM
compilation steps, which necessarily deannotate the FROM elements and do
things like compute joinedloads etc., which makes it not an appropriate
candidate for the :meth:`_sql.Select.select_from` method. Additionally adds
a new parameter
:paramref:`_sql.Select.with_only_columns.maintain_column_froms` that
transfers this collection to :meth:`_sql.Select.select_from` before
replacing the columns collection.

In addition, the :attr:`_sql.Select.froms` is renamed to
:meth:`_sql.Select.get_final_froms`, to stress that this collection is not
a simple accessor and is instead calculated given the full state of the
object, which can be an expensive call when used in an ORM context.

Additionally fixes a regression involving the
:func:`_orm.with_only_columns` function to support applying criteria to
column elements that were replaced with either
:meth:`_sql.Select.with_only_columns` or :meth:`_orm.Query.with_entities` ,
which had broken as part of 🎫`6503` released in 1.4.19.

Fixes: #6808

Change-Id: Ib5d66cce488bbaca06dab4f68fb5cdaa73e8823e
2021-08-07 14:47:29 -04:00
Mike Bayer 9de57843a3 dont qualify literal_binds with literal_execute
this appears to be unnecessary and prevents end-user
literal_binds case from working.

Fixed issue where the ``literal_binds`` compiler flag, as used externally
to render bound parameters inline, would fail to work when used with a
certain class of parameters known as "literal_execute", which covers things
like LIMIT and OFFSET values for dialects where the drivers don't allow a
bound parameter, such as SQL Server's "TOP" clause.  The issue locally
seemed to affect only the MSSQL dialect.

Fixes: #6863
Change-Id: Ia74cff5b0107b129a11b9b965883552b2962e449
2021-08-07 12:13:57 -04:00
Mike Bayer 3729a070d2 accommodate for untracked boundparam lambda in offline_string
Fixed an issue in the ``CacheKey.to_offline_string()`` method used by the
dogpile.caching example where attempting to create a proper cache key from
the special "lambda" query generated by the lazy loader would fail to
include the parameter values, leading to an incorrect cache key.

Fixes: #6858
Change-Id: Ice27087583c6f3ff79cf7d5b879e5dd0a4e58158
2021-08-05 19:19:02 -04:00
Mike Bayer 1ccaac8293 accommodate for cloned bindparams w/ maintain_key
Fixed issue where a bound parameter object that was "cloned" would cause a
name conflict in the compiler, if more than one clone of this parameter
were used at the same time in a single statement. This could occur in
particular with things like ORM single table inheritance queries that
indicated the same "discriminator" value multiple times in one query.

Fixes: #6824
Change-Id: Iba7a786fc5a2341ff7d07fc666d24ed790ad4fe8
2021-07-29 10:12:04 -04:00
Gord Thompson c6b1d24fe7 Modernize tests - dml_whereclause
Fixed issue where the unit of work would internally use a 2.0-deprecated
SQL expression form, emitting a deprecation warning when SQLALCHEMY_WARN_20
were enabled.

Fixes: #6812
Change-Id: I0a031e728527a1c3382848b6ddc793939362b128
2021-07-26 10:08:30 -06:00
mike bayer 54ca40b8b3 Merge "Modernize tests - legacy_select" 2021-07-21 21:23:37 +00:00
mike bayer 79a27c9fcb Merge "dont warn for dictionary passed positionally" 2021-07-21 21:22:46 +00:00
Gord Thompson c2ea2b7308 Modernize tests - legacy_select
Change-Id: I04057cc3d3f93de60b02999803e2ba6a23cdf68d
2021-07-21 16:14:43 -04:00
Mike Bayer 27ec492919 dont warn for dictionary passed positionally
Fixed issue where use of the :paramref:`_sql.case.whens` parameter passing
a dictionary positionally and not as a keyword argument would emit a 2.0
deprecation warning, referring to the deprecation of passing a list
positionally. The dictionary format of "whens", passed positionally, is
still supported and was accidentally marked as deprecated.

Removes warning filter for case statement.

Fixes: #6786
Change-Id: I8efd1882563773bec89ae5e34f0dfede77fc4683
2021-07-21 16:00:12 -04:00
Mike Bayer a34a4af8a8 implement cache key for return_defaults token
Fixed critical caching issue where the ORM's persistence feature using
INSERT..RETURNING would cache an incorrect query when mixing the "bulk
save" and standard "flush" forms of INSERT.

Fixes: #6793
Change-Id: Ifeb61c1226d3fa6d5e1c2e29b6f5ff77a27d6a2d
2021-07-21 13:57:22 -04:00
Mike Bayer b932b04b65 reset key/name when TableValuedColumn is adapted
Fixed issue in new :meth:`_schema.Table.table_valued` method where the
resulting :class:`_sql.TableValuedColumn` construct would not respond
correctly to alias adaptation as is used throughout the ORM, such as for
eager loading, polymorphic loading, etc.

Fixes: #6775
Change-Id: I77cec4b6e1b1003f2b6be242b54ada8e4a435250
2021-07-16 10:14:56 -04:00
Mike Bayer 03794d40f3 limit None->null coercion to not occur with crud
Fixed issue where type-specific bound parameter handlers would not be
called upon in the case of using the :meth:`_sql.Insert.values` method with
the Python ``None`` value; in particular, this would be noticed when using
the :class:`_types.JSON` datatype as well as related PostgreSQL specific
types such as :class:`_postgresql.JSONB` which would fail to encode the
Python ``None`` value into JSON null, however the issue was generalized to
any bound parameter handler in conjunction with this specific method of
:class:`_sql.Insert`.

The issue with coercions forcing out ``null()`` may still impact
SQL expression usage as well; the change here is limited to crud
as the behavior there is relevant to some use cases, which may
need to be evaluated separately.

Fixes: #6770
Change-Id: If53edad811b37dada7578a89daf395628db058a6
2021-07-15 15:09:28 -04:00
Mike Bayer 79a3dafb14 Ensure alias traversal block works when adapt_from_selectables present
Fixed regression which appeared in version 1.4.3 due to 🎫`6060`
where rules that limit ORM adaptation of derived selectables interfered
with other ORM-adaptation based cases, in this case when applying
adaptations for a :func:`_orm.with_polymorphic` against a mapping which
uses a :func:`_orm.column_property` which in turn makes use of a scalar
select that includes a :func:`_orm.aliased` object of the mapped table.

Fixes: #6762
Change-Id: Ice3dc34b97d12b59f044bdc0c5faaefcc4015227
2021-07-14 13:28:25 -04:00
mike bayer 913cade0a1 Merge "Modernize tests - union" 2021-07-13 19:17:28 +00:00
Mike Bayer a0953bb709 Adjust CTE recrusive col list to accommodate dupe col names
Fixed issue in CTE constructs where a recursive CTE that referred to a
SELECT that has duplicate column names, which are typically deduplicated
using labeling logic in 1.4, would fail to refer to the deduplicated label
name correctly within the WITH clause.

As part of this change we are also attempting to remove the
behavior of SelectStatementGrouping forcing off the "asfrom"
contextual flag, which will have the result of additional labeling
being applied to some UNION and similar statements when they are
interpreted as subqueries.  To maintain compatibility with
"grouping", the Grouping/SelectStatementGrouping are now broken
out into two separate compiler cases, as the "asfrom" logic appears
to be tailored towards table valued SELECTS as column expressions.

Fixes: #6710
Change-Id: I8af07a5c670dbe5736cd9f16084ef82f5e4c8642
2021-07-13 10:25:52 -04:00
mike bayer 673ca806b3 Merge "labeling refactor" 2021-07-13 14:25:13 +00:00
Mike Bayer 707e5d70fc labeling refactor
To service #6718 and #6710, the system by which columns are
given labels in a SELECT statement as well as the system that
gives them keys in a .c or .selected_columns collection have
been refactored to provide a single source of truth for
both, in constrast to the previous approach that included
similar logic repeated in slightly different ways.

Main ideas:

1. ColumnElement attributes ._label, ._anon_label, ._key_label
   are renamed to include the letters "tq", meaning
   "table-qualified" - these labels are only used when rendering
   a SELECT that has LABEL_STYLE_TABLENAME_PLUS_COL for its
   label style; as this label style is primarily legacy, the
   "tq" names should be isolated so that in a 2.0 style application
   these aren't being used at all

2. The means by which the "labels" and "proxy keys" for the elements
   of a SELECT has been centralized to a single source of truth;
   previously, the three of _generate_columns_plus_names,
   _generate_fromclause_column_proxies, and _column_naming_convention
   all had duplicated rules between them, as well as that there
   were a little bit of labeling rules in compiler._label_select_column
   as well; by this we mean that the various "anon_label" "anon_key"
   methods on ColumnElement were called by all four of these methods,
   where there were many cases where it was necessary that one method
   comes up with the same answer as another of the methods.  This
   has all been centralized into _generate_columns_plus_names
   for all the names except the "proxy key", which is generated
   by _column_naming_convention.

3. compiler._label_select_column has been rewritten to both not make
   any naming decisions nor any "proxy key" decisions, only whether
   to label or not to label; the _generate_columns_plus_names method
   gives it the information, where the proxy keys come from
   _column_naming_convention; previously, these proxy keys were matched
   based on restatement of similar (but not really the same) logic in
   two places.   The heuristics of "whether to label or not to label"
   are also reorganized to be much easier to read and understand.

4. a new method compiler._label_returning_column is added for dialects
   to use in their "generate returning columns" methods.   A
   github search reveals a small number of third party dialects also
   doing this using the prior _label_select_column method so we
   try to make sure _label_select_column continues to work the
   exact same way for that specific use case; for the "SELECT" use
   case it now needs

5. After some attempts to do it different ways, for the case where
   _proxy_key is giving us some kind of anon label, we are hard
   changing it to "_no_label" right now, as there's not currently
   a way to fully match anonymized labels from stmt.c or
   stmt.selected_columns to what will be in the result map.  The
   idea of "_no_label" is to encourage the user to use label('name')
   for columns they want to be able to target by string name that
   don't have a natural name.

Change-Id: I7a92a66f3a7e459ccf32587ac0a3c306650daf11
2021-07-12 18:50:29 -04:00
Gord Thompson f11b221a35 Modernize tests - union
Change-Id: I2ccb714a249350f23e2b5f78f5f9ffb0d4f7efb0
2021-07-12 16:44:35 -06:00
mike bayer 18dba87757 Merge "implement independent CTEs" 2021-07-12 21:53:11 +00:00
mike bayer b7791290ed Merge "Modernize tests - select(whereclause)" 2021-07-12 21:52:09 +00:00
Mike Bayer 204ff1f60c implement independent CTEs
Added new method :meth:`_sql.HasCTE.add_cte` to each of the
:func:`_sql.select`, :func:`_sql.insert`, :func:`_sql.update` and
:func:`_sql.delete` constructs. This method will add the given
:class:`_sql.CTE` as an "independent" CTE of the statement, meaning it
renders in the WITH clause above the statement unconditionally even if it
is not otherwise referenced in the primary statement. This is a popular use
case on the PostgreSQL database where a CTE is used for a DML statement
that runs against database rows independently of the primary statement.

Fixes: #6752
Change-Id: Ibf635763e40269cbd10f4c17e208850d8e8d0188
2021-07-12 17:10:58 -04:00
Mike Bayer 2aae37f93b represent tablesample.sampling as FunctionElement in all cases
Fixed regression where the :func:`_sql.tablesample` construct would fail to
be executable when constructed given a floating-point sampling value not
embedded within a SQL function.

Fixes: #6735
Change-Id: I557bcd4bdbffc4329ad69d5659ba99b1c8deb554
2021-07-11 19:40:59 -04:00
Gord Thompson 4ff4760fad Modernize tests - select(whereclause)
Change-Id: I306cfbea9920b35100e3087dcc21d7ffa6c39c55
2021-07-04 15:56:40 -06:00
Mike Bayer 7ed6aee275 clear new Query._memoized_select_entities in _from_selectable
Fixed regression caused in 1.4.19 due to #6503 and related involving
:meth:`_orm.Query.with_entities` where the new structure used would be
inappropriately transferred to an enclosing :class:`_orm.Query` when making
use of set operations such as :meth:`_orm.Query.union`, causing the JOIN
instructions within to be applied to the outside query as well.

Fixes: #6698
Change-Id: Ia9f294215ebc01330d142a0a3e5be9d02be9380f
2021-06-30 16:05:34 -04:00
Kai Mueller 7e5e40ff84 Fix missing None handling of Table.prefixes
Fixed issue where passing ``None`` for the value of
:paramref:`_schema.Table.prefixes` would not store an empty list, but
rather the constant ``None``, which may be unexpected by third party
dialects. The issue is revealed by a usage in recent versions of Alembic
that are passing ``None`` for this value. Pull request courtesy Kai
Mueller.

Fixes: #6685
Closes: #6672
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/6672
Pull-request-sha: b79aca0ee4

Change-Id: I758641c6fbde6f2607d074fecea7efa6728aeea0
2021-06-28 10:26:01 -04:00
jason3gb 791f1d9407 Add "impl" parameter to PickleType
Add a impl parameter to :class:`_types.PickleType` constructor, allowing
any arbitary type to be used in place of the default implementation of
:class:`_types.LargeBinary`. Pull request courtesy jason3gb.

Fixes: #6646
Closes: #6657
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/6657
Pull-request-sha: e49bcd368d

Change-Id: Ib79f3b0ebbc94393f673f5a5ba6558260083d0cf
2021-06-24 12:22:20 -04:00
Mike Bayer cdd041ea60 consider "*" col as textual ordered
Fixed old issue where a :func:`_sql.select()` made against the token "*",
which then yielded exactly one column, would fail to correctly organize the
``cursor.description`` column name into the keys of the result object.

Fixes: #6665
Change-Id: Ie8c00f62998972ad4a19a750d2642d00fde006f6
2021-06-23 09:49:11 -04:00
Mike Bayer 2cf8c5868c Export deferred columns but not col props; fix CTE labeling
Refined the behavior of ORM subquery rendering with regards to deferred
columns and column properties to be more compatible with that of 1.3 while
also providing for 1.4's newer features. As a subquery in 1.4 does not make
use of loader options, including :func:`_orm.deferred`, a subquery that is
against an ORM entity with deferred attributes will now render those
deferred attributes that refer directly to mapped table columns, as these
are needed in the outer SELECT if that outer SELECT makes use of these
columns; however a deferred attribute that refers to a composed SQL
expression as we normally do with :func:`_orm.column_property` will not be
part of the subquery, as these can be selected explicitly if needed in the
subquery. If the entity is being SELECTed from this subquery, the column
expression can still render on "the outside" in terms of the derived
subquery columns. This produces essentially the same behavior as when
working with 1.3. However in this case the fix has to also make sure that
the ``.selected_columns`` collection of an ORM-enabled :func:`_sql.select`
also follows these rules, which in particular allows recursive CTEs to
render correctly in this scenario, which were previously failing to render
correctly due to this issue.

As part of this change the _exported_columns_iterator() method has been
removed and logic simplified to use ._all_selected_columns from any
SelectBase object where _exported_columns_iterator() was used before.
Additionally sets up UpdateBase to include ReturnsRows in its hierarchy;
the literal point of ReturnsRows was to be a common base for UpdateBase
and SelectBase so it was kind of weird it wasn't there.

Fixes: #6661

Fixed issue in CTE constructs mostly relevant to ORM use cases where a
recursive CTE against "anonymous" labels such as those seen in ORM
``column_property()`` mappings would render in the
``WITH RECURSIVE xyz(...)`` section as their raw internal label and not a
cleanly anonymized name.

Fixes: #6663
Change-Id: I26219d4d8e6c0915b641426e9885540f74fae4d2
2021-06-22 17:25:37 -04:00
Mike Bayer 5b3e887f46 memoize current options and joins w with_entities/with_only_cols
Fixed further regressions in the same area as that of 🎫`6052` where
loader options as well as invocations of methods like
:meth:`_orm.Query.join` would fail if the left side of the statement for
which the option/join depends upon were replaced by using the
:meth:`_orm.Query.with_entities` method, or when using 2.0 style queries
when using the :meth:`_sql.Select.with_only_columns` method. A new set of
state has been added to the objects which tracks the "left" entities that
the options / join were made against which is memoized when the lead
entities are changed.

Fixes: #6503
Fixes: #6253
Change-Id: I211b2af98b0b20d1263fb15dc513884dcc5de6a4
2021-06-17 09:48:52 -04:00
Mike Bayer bface2e2fa repair Join.is_derived_from() to not rely on simple identity
Fixed issue where query production for joinedload against a complex left
hand side involving joined-table inheritance could fail to produce a
correct query, due to a clause adaption issue.

Fixes: #6595
Change-Id: Id4b839d52447cdc103b392dd8946c4cfa7a829e1
2021-06-07 17:48:55 -04:00
Mike Bayer 460bed7cfd Fix adaption in AnnotatedLabel; repair needless expense in coercion
Fixed regression involving clause adaption of labeled ORM compound
elements, such as single-table inheritance discriminator expressions with
conditionals or CASE expressions, which could cause aliased expressions
such as those used in ORM join / joinedload operations to not be adapted
correctly, such as referring to the wrong table in the ON clause in a join.

This change also improves a performance bump that was located within the
process of invoking :meth:`_sql.Select.join` given an ORM attribute
as a target.

Fixes: #6550
Change-Id: I98906476f0cce6f41ea00b77c789baa818e9d167
2021-05-28 10:35:51 -04:00
Federico Caselli debeea97ee Update black flak8 and zimports
Change-Id: I488c9557eda390e4a88319affd4c8813ee274f80
2021-05-12 22:10:19 +02:00
mike bayer f6329060f1 Merge "allow CTE to be direct DML target" 2021-05-11 18:09:36 +00:00
Mike Bayer 07ab6441ea allow CTE to be direct DML target
Implemented support for a :class:`_sql.CTE` construct to be used directly
as the target of a :func:`_sql.delete` construct, i.e. "WITH ... AS cte
DELETE FROM cte". This appears to be a useful feature of SQL Server.

The CTE is now generally usable as a DML target table however
it's not clear if this syntax is valid beyond the use case of
DELETE itself.

Fixes: #6464
Change-Id: I3aac6fae2a1abb39bc0ffa87a044f5eb4f90f026
2021-05-11 08:39:24 -04:00
Mike Bayer b146a0c641 set bindparam.expanding in coercion again
Adjusted the logic added as part of 🎫`6397` in 1.4.12 so that
internal mutation of the :class:`.BindParameter` object occurs within the
clause construction phase as it did before, rather than in the compilation
phase. In the latter case, the mutation still produced side effects against
the incoming construct and additionally could potentially interfere with
other internal mutation routines.

In order to solve the issue of the correct operator being present
on the BindParameter.expand_op, we necessarily have to expand the
BinaryExpression._negate() routine to flip the operator on the
BindParameter also.

Fixes: #6460
Change-Id: I1e53a9aeee4de4fc11af51d7593431532731561b
2021-05-10 23:42:41 -04:00
mike bayer c99c93fd64 Merge "don't cache TypeDecorator by default" 2021-05-06 21:12:48 +00:00
Mike Bayer 6967b45020 don't cache TypeDecorator by default
The :class:`.TypeDecorator` class will now emit a warning when used in SQL
compilation with caching unless the ``.cache_ok`` flag is set to ``True``
or ``False``. ``.cache_ok`` indicates that all the parameters passed to the
object are safe to be used as a cache key, ``False`` means they are not.

Fixes: #6436
Change-Id: Ib1bb7dc4b124e38521d615c2e2e691e4915594fb
2021-05-06 13:57:43 -04:00
mike bayer 03d922d4ee Merge "Parenthesize for empty not in" 2021-05-05 16:36:08 +00:00
Mike Bayer 5af854606b Parenthesize for empty not in
Fixed regression caused by the "empty in" change just made in
🎫`6397` 1.4.12 where the expression needs to be parenthesized for
the "not in" use case, otherwise the condition will interfere with the
other filtering criteria.

also amends StrSQLCompiler to use the newer "empty IN" style for
its compilation process.

Fixes: #6428
Change-Id: I182a552fc0d3065a9e38c0f4ece2deb143735c36
2021-05-05 09:54:46 -04:00
Mike Bayer d6ec248fa7 Establish deprecation path for CursorResult.keys()
Established a deprecation path for calling upon the
:meth:`_cursor.CursorResult.keys` method for a statement that returns no
rows to provide support for legacy patterns used by the "records" package
as well as any other non-migrated applications. Previously, this would
raise :class:`.ResourceClosedException` unconditionally in the same way as
it does when attempting to fetch rows. While this is the correct behavior
going forward, the :class:`_cursor.LegacyCursorResult` object will now in
this case return an empty list for ``.keys()`` as it did in 1.3, while also
emitting a 2.0 deprecation warning. The :class:`_cursor.CursorResult`, used
when using a 2.0-style "future" engine, will continue to raise as it does
now.

Fixes: #6427
Change-Id: I4148f28c88039e4141deeab28b1a5994e6d6e098
2021-05-04 13:49:43 -04:00
Mike Bayer 5cde12d816 Support filter_by() from columns, functions, Core SQL
Fixed regression where :meth:`_orm.Query.filter_by` would not work if the
lead entity were a SQL function or other expression derived from the
primary entity in question, rather than a simple entity or column of that
entity. Additionally, improved the behavior of
:meth:`_sql.Select.filter_by` overall to work with column expressions even
in a non-ORM context.

Fixes: #6414
Change-Id: I316b5bf98293bec1ede08787f6181dd14be85419
2021-05-01 11:54:21 -04:00
Mike Bayer a47c158a9a track_on needs to be a fixed size, support sub-tuples
Fixed regression in ``selectinload`` loader strategy that would cause it to
cache its internal state incorrectly when handling relationships that join
across more than one column, such as when using a composite foreign key.
The invalid caching would then cause other loader operations to fail.

Fixes: #6410
Change-Id: I9f95ccca3553e7fd5794c619be4cf85c02b04626
2021-04-30 12:35:28 -04:00
mike bayer d264cb8529 Merge "Ensure iterable passed to Select is not a mapped class" 2021-04-29 21:28:32 +00:00