oslo.db/oslo_db/sqlalchemy/orm.py
Mike Bayer af4b2263e4 Resolve SAWarning in Query.soft_delete()
We currently see a lot of warnings like this from
the soft_delete() method:

  sqlalchemy.exc.SAWarning: Evaluating non-mapped column expression
  'updated_at' onto ORM instances; this is a deprecated use case.
  Please make use of the actual mapped columns in ORM-evaluated
  UPDATE / DELETE expressions.

This is because the "evaluate" synchronization strategy would like
to search for objects and update them based on the UPDATE criteria
passed, however the columns given, literal_column('id'),
literal_column('updated_at'), are not mapped to anything. The
evaluator has to make a guess that the string contained in these
expressions should be matched to a mapped attribute on the given
entity and this guess was first removed in [1], then added back in
[2] with a warning (likely since oslo.db is invoking it).

This uses the actual entity-mapped column for the query rather
than the literal string column.

[1] https://docs.sqlalchemy.org/en/latest/changelog/changelog_12.html#change-b1e620dece39006ab44c47044e9a6fee
[2] https://docs.sqlalchemy.org/en/latest/changelog/changelog_12.html#change-dff3a469788c81a46440584406cb22be

Change-Id: I192e84ce757d12d33085a209dd58d8ea46fb90fb
Closes-Bug: #1814199
2019-02-01 11:57:40 -05:00

67 lines
2.6 KiB
Python

# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""SQLAlchemy ORM connectivity and query structures.
"""
from oslo_utils import timeutils
import sqlalchemy.orm
from oslo_db.sqlalchemy import update_match
class Query(sqlalchemy.orm.query.Query):
"""Subclass of sqlalchemy.query with soft_delete() method."""
def soft_delete(self, synchronize_session='evaluate'):
entity = self.column_descriptions[0]['entity']
return self.update({'deleted': entity.id,
'updated_at': entity.updated_at,
'deleted_at': timeutils.utcnow()},
synchronize_session=synchronize_session)
def update_returning_pk(self, values, surrogate_key):
"""Perform an UPDATE, returning the primary key of the matched row.
This is a method-version of
oslo_db.sqlalchemy.update_match.update_returning_pk(); see that
function for usage details.
"""
return update_match.update_returning_pk(self, values, surrogate_key)
def update_on_match(self, specimen, surrogate_key, values, **kw):
"""Emit an UPDATE statement matching the given specimen.
This is a method-version of
oslo_db.sqlalchemy.update_match.update_on_match(); see that function
for usage details.
"""
return update_match.update_on_match(
self, specimen, surrogate_key, values, **kw)
class Session(sqlalchemy.orm.session.Session):
"""oslo.db-specific Session subclass."""
def get_maker(engine, autocommit=True, expire_on_commit=False):
"""Return a SQLAlchemy sessionmaker using the given engine."""
return sqlalchemy.orm.sessionmaker(bind=engine,
class_=Session,
autocommit=autocommit,
expire_on_commit=expire_on_commit,
query_cls=Query)