Skip to content

feat: extensions - #30

Open
RaRhAeu wants to merge 12 commits into
mainfrom
feat/versioned
Open

RaRhAeu wants to merge 12 commits into
mainfrom
feat/versioned

Conversation

@RaRhAeu

@RaRhAeu RaRhAeu commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor
  • versioned models
  • auditable models
  • outbox pattern
  • json_set operations
  • vectors support

@github-actions

github-actions Bot commented Aug 14, 2026 •

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
__init__.py130100% 
audit.py240100% 
cluster.py1100100% 
database.py1800100% 
functools.py190100% 
imports.py410100% 
mixins.py940100% 
orm.py320100% 
query_builder.py1520100% 
registry.py240100% 
routing.py1490100% 
settings.py290100% 
tracker.py370100% 
typing.py240100% 
uow.py820100% 
utils.py100100% 
cron
   __init__.py40100% 
   manager.py1150100% 
   models.py190100% 
   repository.py360100% 
   utils.py90100% 
dialects
   __init__.py00100% 
   mysql.py240100% 
   postgres.py560100% 
   sqlite.py380100% 
i18n
   __init__.py60100% 
   expression.py350100% 
   mixin.py180100% 
   repository.py140100% 
   translatable.py1130100% 
   translation.py990100% 
integrations
   __init__.py00100% 
   eventiq.py190100% 
   fastapi.py610100% 
outbox
   __init__.py50100% 
   config.py390100% 
   models.py210100% 
   relay.py640100% 
   repository.py1100100% 
pagination
   __init__.py50100% 
   abc.py460100% 
   cursor.py520100% 
   models.py380100% 
   offset_limit.py710100% 
   page.py720100% 
repository
   __init__.py50100% 
   auditable.py1920100% 
   base.py3100100% 
   soft_delete.py1010100% 
   versioned.py860100% 
types
   __init__.py40100% 
   datetime.py440100% 
   json.py3700100% 
   pydantic.py440100% 
   uuid.py560100% 
   vector.py1140100% 
vectors
   __init__.py60100% 
   loader.py37489%32, 78–79, 81
   mixins.py480100% 
   models.py190100% 
   repository.py912968%53, 97–98, 153–156, 164–169, 175–181, 191, 227, 230–233, 272, 281–282
TOTAL37363399% 

Tests Skipped Failures Errors Time
6288 3195 💤 0 ❌ 0 🔥 31.125s ⏱️

@RaRhAeu RaRhAeu changed the title feat: versioned models feat: extensions Aug 24, 2026
RaRhAeu and others added 10 commits August 24, 2026 23:16
Both sides are kept. Beyond the mechanical resolution:

- pyproject: main's 1.0.0 bump, alembic-postgresql-enum and self-referential
  `standard` extra, on top of this branch's reshaped extras (anyio is a core
  dependency, `outbox` is gone and `vectors` covers both backends). The docs
  and the sqlite loader's ImportError follow.
- e2e: the `postgres` backend runs the pgvector image, since the vector suite
  needs the extension. `postgres17` cannot hold the uuidv7() defaulted tables
  at all, so the vector tables move behind `vector_search` and
  UUIDAuditArticle behind `server_side_uuidv7`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TranslatedRepository was declared as a bare SQLAlchemyRepository, so
TranslatedRepository[Article] raised "not a generic class" and the model
could only be set by hand -- unlike every other repository in the library.

Add TranslatableBase and the TranslatableModel type var, mirroring the
SoftDeleteBase / SoftDeleteModel pair, and bind the repository to them. A
model carrying no translation table now raises TypeError on subclassing,
the way SoftDeleteRepository validates its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JSON_EXTRACT hands back a quoted JSON scalar there, so LIKE and ordering
matched against the quotes as well. An equality comparison coerces its
operand to JSON and agrees either way, which is what made the rest of the
surface look correct.

Found by the new e2e suite: every LIKE query over a TranslatedString
column returned nothing on both backends.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
SQLAlchemy never leaves version_id_generator as True -- it normalises the
default into a callable incrementing the version it is handed -- so the
branch meant to emit `version + 1` was unreachable and the callable one
ran instead, calling it with None and yielding 1 every time.

An integer version column therefore stayed pinned at 1 across every
update, silently voiding the optimistic concurrency guard: update_if_match
could never tell a stale row from a fresh one. Key the decision off the
column type instead, and skip the bump in bulk_update, where an executemany
cannot carry an expression.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
i18n shipped with tests for the two locale slots alone: translatable.py
sat at 35%, translation.py at 48%, mixin.py at 44%. Cover both backends --
the TranslatedString column and the translation table -- across the
Translation value type, the pydantic hooks, the multi-locale helpers, the
per-dialect compilation and the repository join, plus an e2e suite running
all of it against the five real backends.

Also cover the integer version counter and the server managed guard, the
repository's database attribute, JSON literal rendering and the vector
type's non-list paths, and mark the three dependency-absent ImportError
guards no cover -- the extras are installed in this environment, so they
were never reachable.

Unit coverage 95% -> 99%.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
i18n was not mentioned anywhere in docs/ or the README despite shipping
two storage backends. Add a narrative page covering both, the startup
callables, the multi-locale helpers and per-backend behaviour, and note
that mypy rejects translation_table() as a dynamic base.

The api reference had no i18n and no vectors section either, though
vectors ships a full page of its own; add both.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant