Fix with_entities usage in db queries

In order to retrieve shares with filters
pertaining to separate tables (shares, instances, metadata,
etc), we need to perform joined loads of those
respective database tables as necessary. After the
join, the query cannot select entities due to
Github issue #6253 - The following is an error when
the pattern is used:

sqlalchemy.exc.ArgumentError: Query has only expression-based entities - can't find property named "share_metadata".

sqlalchemy 1.4 has a performance improvement that
delays query processing [2] and disallows this
pattern of usage; we can use a query.count() instead.

In another instance, we can perform joins selectively
only if asked for.

[1] https://github.com/sqlalchemy/sqlalchemy/issues/625
[2] https://docs.sqlalchemy.org/en/14/changelog/migration_14.html#many-core-and-orm-statement-objects-now-perform-much-of-their-construction-and-validation-in-the-compile-phase

Change-Id: I8aa196c171bbc224cec06f517ea22c4e91cbc06a
Closes-Bug: #1926399
Signed-off-by: Goutham Pacha Ravi <gouthampravi@gmail.com>
(cherry picked from commit 6ace54c260)
This commit is contained in:
Goutham Pacha Ravi 2021-05-19 17:14:24 -07:00
parent 3532f5d654
commit 7116f839e2
1 changed files with 6 additions and 9 deletions

View File

@ -46,7 +46,6 @@ from sqlalchemy import MetaData
from sqlalchemy import or_ from sqlalchemy import or_
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from sqlalchemy.orm import subqueryload from sqlalchemy.orm import subqueryload
from sqlalchemy.sql import distinct
from sqlalchemy.sql.expression import literal from sqlalchemy.sql.expression import literal
from sqlalchemy.sql.expression import true from sqlalchemy.sql.expression import true
from sqlalchemy.sql import func from sqlalchemy.sql import func
@ -2163,8 +2162,7 @@ def _share_get_all_with_filters(context, project_id=None, share_server_id=None,
# NOTE(carloss): Count must be calculated before limit and offset are # NOTE(carloss): Count must be calculated before limit and offset are
# applied into the query. # applied into the query.
if show_count: if show_count:
count = query.with_entities( count = query.count()
func.count(distinct(models.Share.id))).scalar()
if 'limit' in filters: if 'limit' in filters:
offset = filters.get('offset', 0) offset = filters.get('offset', 0)
@ -5266,11 +5264,7 @@ def _share_group_snapshot_get_all(
sort_dir = 'desc' sort_dir = 'desc'
query = model_query( query = model_query(
context, models.ShareGroupSnapshot, session=session, read_deleted='no', context, models.ShareGroupSnapshot, session=session, read_deleted='no')
).options(
joinedload('share_group'),
joinedload('share_group_snapshot_members'),
)
# Apply filters # Apply filters
if not filters: if not filters:
@ -5295,7 +5289,10 @@ def _share_group_snapshot_get_all(
raise exception.InvalidInput(reason=msg) raise exception.InvalidInput(reason=msg)
if detailed: if detailed:
return query.all() return query.options(
joinedload('share_group'),
joinedload('share_group_snapshot_members')
).all()
else: else:
query = query.with_entities(models.ShareGroupSnapshot.id, query = query.with_entities(models.ShareGroupSnapshot.id,
models.ShareGroupSnapshot.name) models.ShareGroupSnapshot.name)