feat: add TransactionMetaPlugin to save comments when applicable
This commit is contained in:
parent
09e4ef6a1e
commit
b19f565aa1
3 changed files with 87 additions and 3 deletions
|
|
@ -28,7 +28,7 @@ import socket
|
||||||
|
|
||||||
from sqlalchemy.orm import configure_mappers
|
from sqlalchemy.orm import configure_mappers
|
||||||
from sqlalchemy_continuum import make_versioned
|
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.conf import WuttaConfigExtension
|
||||||
from wuttjamaican.util import load_object
|
from wuttjamaican.util import load_object
|
||||||
|
|
@ -66,6 +66,20 @@ class WuttaContinuumConfigExtension(WuttaConfigExtension):
|
||||||
|
|
||||||
For more about SQLAlchemy-Continuum see
|
For more about SQLAlchemy-Continuum see
|
||||||
:doc:`sqlalchemy-continuum:intro`.
|
: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
|
# only do this if config enables it
|
||||||
if not config.get_bool(
|
if not config.get_bool(
|
||||||
|
|
@ -86,7 +100,7 @@ class WuttaContinuumConfigExtension(WuttaConfigExtension):
|
||||||
raise RuntimeError("something not right, app already has model")
|
raise RuntimeError("something not right, app already has model")
|
||||||
|
|
||||||
# let sqlalchemy-continuum do its thing
|
# let sqlalchemy-continuum do its thing
|
||||||
make_versioned(plugins=[plugin()])
|
make_versioned(plugins=[TransactionMetaPlugin(), plugin()])
|
||||||
|
|
||||||
# must load model *between* prev and next calls
|
# must load model *between* prev and next calls
|
||||||
app.get_model()
|
app.get_model()
|
||||||
|
|
@ -148,3 +162,16 @@ class WuttaContinuumPlugin(Plugin):
|
||||||
kwargs["user_id"] = user_id
|
kwargs["user_id"] = user_id
|
||||||
|
|
||||||
return kwargs
|
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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch, Mock
|
||||||
|
|
||||||
from wuttjamaican.testing import ConfigTestCase, DataTestCase
|
from wuttjamaican.testing import ConfigTestCase, DataTestCase
|
||||||
|
|
||||||
|
|
@ -71,3 +71,20 @@ class TestWuttaContinuumPlugin(DataTestCase):
|
||||||
plugin.transaction_args(None, self.session),
|
plugin.transaction_args(None, self.session),
|
||||||
{"remote_addr": "127.0.0.1", "user_id": "some-random-uuid"},
|
{"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")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue