|
11 | 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | 12 | # See the License for the specific language governing permissions and |
13 | 13 | # limitations under the License. |
| 14 | +import datetime |
14 | 15 | import os |
15 | 16 | from typing import Optional |
16 | 17 | from sqlalchemy import ( |
|
27 | 28 | select, |
28 | 29 | update, |
29 | 30 | delete, |
| 31 | + event, |
30 | 32 | ) |
31 | 33 | from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column |
32 | 34 | from sqlalchemy.types import REAL |
33 | | -from sqlalchemy.testing import eq_, is_true |
| 35 | +from sqlalchemy.testing import eq_, is_true, is_not_none |
34 | 36 | from sqlalchemy.testing.plugin.plugin_base import fixtures |
35 | 37 |
|
36 | 38 |
|
@@ -238,3 +240,57 @@ class User(Base): |
238 | 240 |
|
239 | 241 | eq_(len(inserted_rows), len(selected_rows)) |
240 | 242 | eq_(set(inserted_rows), set(selected_rows)) |
| 243 | + |
| 244 | + def test_commit_timestamp(self, connection): |
| 245 | + """Ensures commit timestamps are set.""" |
| 246 | + |
| 247 | + class Base(DeclarativeBase): |
| 248 | + pass |
| 249 | + |
| 250 | + class TimestampUser(Base): |
| 251 | + __tablename__ = "timestamp_users" |
| 252 | + ID: Mapped[int] = mapped_column(primary_key=True) |
| 253 | + name: Mapped[str] |
| 254 | + updated_at: Mapped[datetime.datetime] = mapped_column( |
| 255 | + spanner_allow_commit_timestamp=True, |
| 256 | + default=text("PENDING_COMMIT_TIMESTAMP()"), |
| 257 | + ) |
| 258 | + |
| 259 | + @event.listens_for(TimestampUser, "before_update") |
| 260 | + def before_update(mapper, connection, target): |
| 261 | + target.updated_at = text("PENDING_COMMIT_TIMESTAMP()") |
| 262 | + |
| 263 | + engine = connection.engine |
| 264 | + Base.metadata.create_all(engine) |
| 265 | + try: |
| 266 | + with Session(engine) as session: |
| 267 | + session.add(TimestampUser(name="name")) |
| 268 | + session.commit() |
| 269 | + |
| 270 | + with Session(engine) as session: |
| 271 | + users = list( |
| 272 | + session.scalars( |
| 273 | + select(TimestampUser).where(TimestampUser.name == "name") |
| 274 | + ) |
| 275 | + ) |
| 276 | + user = users[0] |
| 277 | + |
| 278 | + is_not_none(user.updated_at) |
| 279 | + created_at = user.updated_at |
| 280 | + |
| 281 | + user.name = "new-name" |
| 282 | + session.commit() |
| 283 | + |
| 284 | + with Session(engine) as session: |
| 285 | + users = list( |
| 286 | + session.scalars( |
| 287 | + select(TimestampUser).where(TimestampUser.name == "new-name") |
| 288 | + ) |
| 289 | + ) |
| 290 | + user = users[0] |
| 291 | + |
| 292 | + is_not_none(user.updated_at) |
| 293 | + is_true(user.updated_at > created_at) |
| 294 | + |
| 295 | + finally: |
| 296 | + Base.metadata.drop_all(engine) |
0 commit comments