@property
def is_select(self) -> bool:
- """return True if this is a SELECT operation."""
+ """return True if this is a SELECT operation.
+
+ .. versionchanged:: 2.0.30 - the attribute is also True for a
+ :meth:`_sql.Select.from_statement` construct that is itself against
+ a :class:`_sql.Select` construct, such as
+ ``select(Entity).from_statement(select(..))``
+
+ """
return self.statement.is_select
+ @property
+ def is_from_statement(self) -> bool:
+ """return True if this operation is a
+ :meth:`_sql.Select.from_statement` operation.
+
+ This is independent from :attr:`_orm.ORMExecuteState.is_select`, as a
+ ``select().from_statement()`` construct can be used with
+ INSERT/UPDATE/DELETE RETURNING types of statements as well.
+ :attr:`_orm.ORMExecuteState.is_select` will only be set if the
+ :meth:`_sql.Select.from_statement` is itself against a
+ :class:`_sql.Select` construct.
+
+ .. versionadded:: 2.0.30
+
+ """
+ return self.statement.is_from_statement
+
@property
def is_insert(self) -> bool:
- """return True if this is an INSERT operation."""
+ """return True if this is an INSERT operation.
+
+ .. versionchanged:: 2.0.30 - the attribute is also True for a
+ :meth:`_sql.Select.from_statement` construct that is itself against
+ a :class:`_sql.Insert` construct, such as
+ ``select(Entity).from_statement(insert(..))``
+
+ """
return self.statement.is_dml and self.statement.is_insert
@property
def is_update(self) -> bool:
- """return True if this is an UPDATE operation."""
+ """return True if this is an UPDATE operation.
+
+ .. versionchanged:: 2.0.30 - the attribute is also True for a
+ :meth:`_sql.Select.from_statement` construct that is itself against
+ a :class:`_sql.Update` construct, such as
+ ``select(Entity).from_statement(update(..))``
+
+ """
return self.statement.is_dml and self.statement.is_update
@property
def is_delete(self) -> bool:
- """return True if this is a DELETE operation."""
+ """return True if this is a DELETE operation.
+
+ .. versionchanged:: 2.0.30 - the attribute is also True for a
+ :meth:`_sql.Select.from_statement` construct that is itself against
+ a :class:`_sql.Delete` construct, such as
+ ``select(Entity).from_statement(delete(..))``
+
+ """
return self.statement.is_dml and self.statement.is_delete
@property
bind_mapper=ctx.bind_mapper,
all_mappers=ctx.all_mappers,
is_select=ctx.is_select,
+ is_from_statement=ctx.is_from_statement,
+ is_insert=ctx.is_insert,
is_update=ctx.is_update,
is_delete=ctx.is_delete,
is_orm_statement=ctx.is_orm_statement,
bind_mapper=None,
all_mappers=[],
is_select=is_select,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=False,
bind_mapper=inspect(User),
all_mappers=[inspect(User), inspect(Address)],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
bind_mapper=None,
all_mappers=[],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=False,
bind_mapper=inspect(User),
all_mappers=[inspect(User)], # Address not in results
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
bind_mapper=inspect(User),
all_mappers=[inspect(User)],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
bind_mapper=inspect(User),
all_mappers=[inspect(User)],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
+ is_update=False,
+ is_delete=False,
+ is_orm_statement=True,
+ is_relationship_load=False,
+ is_column_load=True,
+ lazy_loaded_from=None,
+ ),
+ ],
+ )
+
+ def test_select_from_statement_flags(self):
+ User, Address = self.classes("User", "Address")
+
+ sess = Session(testing.db, future=True)
+
+ canary = self._flag_fixture(sess)
+
+ s1 = select(User).filter_by(id=7)
+ u1 = sess.execute(select(User).from_statement(s1)).scalar_one()
+
+ sess.expire(u1)
+
+ eq_(u1.name, "jack")
+
+ eq_(
+ canary.mock_calls,
+ [
+ call.options(
+ bind_mapper=inspect(User),
+ all_mappers=[inspect(User)],
+ is_select=True,
+ is_from_statement=True,
+ is_insert=False,
+ is_update=False,
+ is_delete=False,
+ is_orm_statement=True,
+ is_relationship_load=False,
+ is_column_load=False,
+ lazy_loaded_from=None,
+ ),
+ call.options(
+ bind_mapper=inspect(User),
+ all_mappers=[inspect(User)],
+ is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
bind_mapper=inspect(User),
all_mappers=[inspect(User)],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
bind_mapper=inspect(Address),
all_mappers=[inspect(Address)],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
bind_mapper=inspect(User),
all_mappers=[inspect(User)],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
bind_mapper=inspect(Address),
all_mappers=[inspect(Address)],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
bind_mapper=inspect(User),
all_mappers=[inspect(User)],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
bind_mapper=inspect(Address),
all_mappers=[inspect(Address), inspect(User)],
is_select=True,
+ is_from_statement=False,
+ is_insert=False,
is_update=False,
is_delete=False,
is_orm_statement=True,
],
)
- def test_update_delete_flags(self):
+ @testing.variation(
+ "stmt_type",
+ [
+ ("insert", testing.requires.insert_returning),
+ ("update", testing.requires.update_returning),
+ ("delete", testing.requires.delete_returning),
+ ],
+ )
+ @testing.variation("from_stmt", [True, False])
+ def test_update_delete_flags(self, stmt_type, from_stmt):
User, Address = self.classes("User", "Address")
sess = Session(testing.db, future=True)
canary = self._flag_fixture(sess)
- sess.execute(
- delete(User)
- .filter_by(id=18)
- .execution_options(synchronize_session="evaluate")
- )
- sess.execute(
- update(User)
- .filter_by(id=18)
- .values(name="eighteen")
- .execution_options(synchronize_session="evaluate")
- )
+ if stmt_type.delete:
+ stmt = (
+ delete(User)
+ .filter_by(id=18)
+ .execution_options(synchronize_session="evaluate")
+ )
+ elif stmt_type.update:
+ stmt = (
+ update(User)
+ .filter_by(id=18)
+ .values(name="eighteen")
+ .execution_options(synchronize_session="evaluate")
+ )
+ elif stmt_type.insert:
+ stmt = insert(User).values(name="eighteen")
+ else:
+ stmt_type.fail()
+
+ if from_stmt:
+ stmt = select(User).from_statement(stmt.returning(User))
+
+ sess.execute(stmt)
eq_(
canary.mock_calls,
bind_mapper=inspect(User),
all_mappers=[inspect(User)],
is_select=False,
- is_update=False,
- is_delete=True,
- is_orm_statement=True,
- is_relationship_load=False,
- is_column_load=False,
- lazy_loaded_from=None,
- ),
- call.options(
- bind_mapper=inspect(User),
- all_mappers=[inspect(User)],
- is_select=False,
- is_update=True,
- is_delete=False,
+ is_from_statement=bool(from_stmt),
+ is_insert=stmt_type.insert,
+ is_update=stmt_type.update,
+ is_delete=stmt_type.delete,
is_orm_statement=True,
is_relationship_load=False,
is_column_load=False,