feat: add TransactionMetaPlugin to save comments when applicable

This commit is contained in:
Lance Edgar 2025-12-18 23:02:08 -06:00
parent 09e4ef6a1e
commit b19f565aa1
3 changed files with 87 additions and 3 deletions

View file

@ -28,7 +28,7 @@ import socket
from sqlalchemy.orm import configure_mappers
from sqlalchemy_continuum import make_versioned
from sqlalchemy_continuum.plugins import Plugin
from sqlalchemy_continuum.plugins import Plugin, TransactionMetaPlugin
from wuttjamaican.conf import WuttaConfigExtension
from wuttjamaican.util import load_object
@ -66,6 +66,20 @@ class WuttaContinuumConfigExtension(WuttaConfigExtension):
For more about SQLAlchemy-Continuum see
:doc:`sqlalchemy-continuum:intro`.
Two plugins are provided to ``make_versioned()``:
The first is ``TransactionMetaPlugin`` for sake of adding
comments (see
:mod:`~sqlalchemy-continuum:sqlalchemy_continuum.plugins.transaction_meta`).
The second by default is :class:`WuttaContinuumPlugin` but you
can override with config:
.. code-block:: ini
[wutta_continuum]
wutta_plugin_spec = poser.db.continuum:PoserContinuumPlugin
"""
# only do this if config enables it
if not config.get_bool(
@ -86,7 +100,7 @@ class WuttaContinuumConfigExtension(WuttaConfigExtension):
raise RuntimeError("something not right, app already has model")
# let sqlalchemy-continuum do its thing
make_versioned(plugins=[plugin()])
make_versioned(plugins=[TransactionMetaPlugin(), plugin()])
# must load model *between* prev and next calls
app.get_model()
@ -148,3 +162,16 @@ class WuttaContinuumPlugin(Plugin):
kwargs["user_id"] = user_id
return kwargs
def before_flush(self, uow, session):
"""
We use this hook to inject the "comment" for current
transaction, if applicable.
This checks the session for the comment; so any session can
specify one like so::
session.info["continuum_comment"] = "hello world"
"""
if comment := session.info.get("continuum_comment"):
uow.current_transaction.meta["comment"] = comment

View file

@ -0,0 +1,40 @@
"""add transaction_meta
Revision ID: 46fb4711411d
Revises: 989392cc191d
Create Date: 2025-12-18 21:22:33.382628
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import wuttjamaican.db.util
# revision identifiers, used by Alembic.
revision: str = "46fb4711411d"
down_revision: Union[str, None] = "989392cc191d"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# transaction_meta
op.create_table(
"transaction_meta",
sa.Column("transaction_id", sa.BigInteger(), nullable=False),
sa.Column("key", sa.Unicode(length=255), nullable=False),
sa.Column("value", sa.UnicodeText(), nullable=True),
sa.PrimaryKeyConstraint(
"transaction_id", "key", name=op.f("pk_transaction_meta")
),
)
def downgrade() -> None:
# transaction_meta
op.drop_table("transaction_meta")

View file

@ -2,7 +2,7 @@
import socket
from unittest.mock import patch
from unittest.mock import patch, Mock
from wuttjamaican.testing import ConfigTestCase, DataTestCase
@ -71,3 +71,20 @@ class TestWuttaContinuumPlugin(DataTestCase):
plugin.transaction_args(None, self.session),
{"remote_addr": "127.0.0.1", "user_id": "some-random-uuid"},
)
def test_before_flush(self):
plugin = self.make_plugin()
meta = {}
txn = Mock(meta=meta)
uow = Mock(current_transaction=txn)
# no comment in session or transaction
plugin.before_flush(uow, self.session)
self.assertNotIn("comment", meta)
# transaction comment matches session
self.session.info["continuum_comment"] = "whaddyaknow"
plugin.before_flush(uow, self.session)
self.assertIn("comment", meta)
self.assertEqual(meta["comment"], "whaddyaknow")