feat(backend+frontend): add is_regex support to dictionary entries

Add support for regex-based dictionary entries across the full stack:

Backend:
- DictionaryEntry model: add is_regex column (Boolean, default False)
- DictionaryEntryCRUD: validate regex on add_entry(), compile on creation
- _enforce_dictionary: match by regex pattern when is_regex=True
- dictionary_filter: support is_regex in filter/query
- metrics: include is_regex entries in metrics calculations
- Alembic migration: 20260604_add_is_regex_to_dictionary_entries
- Merge migration: 351afb8f961a (merge is_regex + composite index heads)

Frontend:
- DictionaryDetailModel: add is_regex field to DictionaryEntry interface,
  EditForm, and addForm; sync edit/add form state with backend schema
This commit is contained in:
2026-06-04 16:16:02 +03:00
parent b823bc559b
commit a1a855e670
8 changed files with 132 additions and 11 deletions

View File

@@ -0,0 +1,38 @@
"""Add is_regex column to dictionary_entries
Revision ID: b2c3d4e5f6a7
Revises: a1b2c3d4e5f6
Create Date: 2026-06-04
Add regex pattern support to terminology dictionary entries.
When is_regex=True, source_term is treated as a regex pattern
instead of a literal substring for matching and enforcement.
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "b2c3d4e5f6a7"
down_revision: Union[str, None] = "a1b2c3d4e5f6"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.add_column(
"dictionary_entries",
sa.Column(
"is_regex",
sa.Boolean(),
nullable=False,
server_default=sa.text("false"),
comment="Whether source_term is a regex pattern",
),
)
def downgrade() -> None:
op.drop_column("dictionary_entries", "is_regex")

View File

@@ -0,0 +1,28 @@
"""merge is_regex and composite index heads
Revision ID: 351afb8f961a
Revises: b2c3d4e5f6a7, c7d8e9f0a1b2
Create Date: 2026-06-04 14:50:00.004262
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '351afb8f961a'
down_revision: Union[str, Sequence[str], None] = ('b2c3d4e5f6a7', 'c7d8e9f0a1b2')
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
pass
def downgrade() -> None:
"""Downgrade schema."""
pass