summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/build/changelog/unreleased_14/7169.rst8
-rw-r--r--doc/build/conf.py1
-rw-r--r--examples/versioned_rows/versioned_map.py4
-rw-r--r--examples/versioned_rows/versioned_rows.py2
-rw-r--r--examples/versioned_rows/versioned_rows_w_versionid.py2
-rw-r--r--examples/versioned_rows/versioned_update_old_row.py40
6 files changed, 29 insertions, 28 deletions
diff --git a/doc/build/changelog/unreleased_14/7169.rst b/doc/build/changelog/unreleased_14/7169.rst
new file mode 100644
index 000000000..e73785545
--- /dev/null
+++ b/doc/build/changelog/unreleased_14/7169.rst
@@ -0,0 +1,8 @@
+.. change::
+ :tags: bug, examples
+ :tickets: 7169
+
+ Repaired the examples in examples/versioned_rows to use SQLAlchemy 1.4 APIs
+ correctly; these examples had been missed when API changes like removing
+ "passive" from ``Session.is_modified()`` were made as well as the
+ ``do_orm_execute()`` event hook were added.
diff --git a/doc/build/conf.py b/doc/build/conf.py
index 2fb5b8e68..1b434fad2 100644
--- a/doc/build/conf.py
+++ b/doc/build/conf.py
@@ -58,6 +58,7 @@ changelog_sections = [
"orm declarative",
"orm querying",
"orm configuration",
+ "examples",
"engine",
"sql",
"schema",
diff --git a/examples/versioned_rows/versioned_map.py b/examples/versioned_rows/versioned_map.py
index 9abbb3e09..c2fa6c2a9 100644
--- a/examples/versioned_rows/versioned_map.py
+++ b/examples/versioned_rows/versioned_map.py
@@ -53,9 +53,7 @@ def before_flush(session, flush_context, instances):
"""
for instance in session.dirty:
- if hasattr(instance, "new_version") and session.is_modified(
- instance, passive=True
- ):
+ if hasattr(instance, "new_version") and session.is_modified(instance):
# make it transient
instance.new_version(session)
diff --git a/examples/versioned_rows/versioned_rows.py b/examples/versioned_rows/versioned_rows.py
index 01067431c..7179d0474 100644
--- a/examples/versioned_rows/versioned_rows.py
+++ b/examples/versioned_rows/versioned_rows.py
@@ -34,7 +34,7 @@ def before_flush(session, flush_context, instances):
for instance in session.dirty:
if not isinstance(instance, Versioned):
continue
- if not session.is_modified(instance, passive=True):
+ if not session.is_modified(instance):
continue
if not attributes.instance_state(instance).has_identity:
diff --git a/examples/versioned_rows/versioned_rows_w_versionid.py b/examples/versioned_rows/versioned_rows_w_versionid.py
index ac5d0f58a..87d246da1 100644
--- a/examples/versioned_rows/versioned_rows_w_versionid.py
+++ b/examples/versioned_rows/versioned_rows_w_versionid.py
@@ -64,7 +64,7 @@ def before_flush(session, flush_context, instances):
for instance in session.dirty:
if not isinstance(instance, Versioned):
continue
- if not session.is_modified(instance, passive=True):
+ if not session.is_modified(instance):
continue
if not attributes.instance_state(instance).has_identity:
diff --git a/examples/versioned_rows/versioned_update_old_row.py b/examples/versioned_rows/versioned_update_old_row.py
index 0da28cf42..049c1a7a0 100644
--- a/examples/versioned_rows/versioned_update_old_row.py
+++ b/examples/versioned_rows/versioned_update_old_row.py
@@ -1,6 +1,6 @@
"""Illustrates the same UPDATE into INSERT technique of ``versioned_rows.py``,
but also emits an UPDATE on the **old** row to affect a change in timestamp.
-Also includes a :meth:`.QueryEvents.before_compile` hook to limit queries
+Also includes a :meth:`.SessionEvents.do_orm_execute` hook to limit queries
to only the most recent version.
"""
@@ -8,22 +8,22 @@ to only the most recent version.
import datetime
import time
+from sqlalchemy import and_
from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy import DateTime
from sqlalchemy import event
from sqlalchemy import inspect
from sqlalchemy import Integer
-from sqlalchemy import literal
from sqlalchemy import String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import attributes
from sqlalchemy.orm import backref
from sqlalchemy.orm import make_transient
from sqlalchemy.orm import make_transient_to_detached
-from sqlalchemy.orm import Query
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session
+from sqlalchemy.orm import with_loader_criteria
Base = declarative_base()
@@ -38,6 +38,9 @@ def current_time():
class VersionedStartEnd(object):
+ start = Column(DateTime, primary_key=True)
+ end = Column(DateTime, primary_key=True)
+
def __init__(self, **kw):
# reduce some verbosity when we make a new object
kw.setdefault("start", current_time() - datetime.timedelta(days=3))
@@ -88,7 +91,7 @@ def before_flush(session, flush_context, instances):
for instance in session.dirty:
if not isinstance(instance, VersionedStartEnd):
continue
- if not session.is_modified(instance, passive=True):
+ if not session.is_modified(instance):
continue
if not attributes.instance_state(instance).has_identity:
@@ -100,27 +103,18 @@ def before_flush(session, flush_context, instances):
session.add(instance)
-@event.listens_for(Query, "before_compile", retval=True)
-def before_compile(query):
+@event.listens_for(Session, "do_orm_execute", retval=True)
+def do_orm_execute(execute_state):
"""ensure all queries for VersionedStartEnd include criteria"""
- for ent in query.column_descriptions:
- entity = ent["entity"]
- if entity is None:
- continue
- insp = inspect(ent["entity"])
- mapper = getattr(insp, "mapper", None)
- if mapper and issubclass(mapper.class_, VersionedStartEnd):
- query = query.enable_assertions(False).filter(
- # using a literal "now" because SQLite's "between"
- # seems to be inclusive. In practice, this would be
- # ``func.now()`` and we'd be using PostgreSQL
- literal(
- current_time() + datetime.timedelta(seconds=1)
- ).between(ent["entity"].start, ent["entity"].end)
- )
-
- return query
+ ct = current_time() + datetime.timedelta(seconds=1)
+ execute_state.statement = execute_state.statement.options(
+ with_loader_criteria(
+ VersionedStartEnd,
+ lambda cls: and_(ct > cls.start, ct < cls.end),
+ include_aliases=True,
+ )
+ )
class Parent(VersionedStartEnd, Base):