refactor: almost final migrations cleanup#1456
Conversation
Bumping the auto increment value has been done since the original sql PR, so it doesn't need to be done on migrations. See e5e7b8a.
The only table that has been added since DB version 6 (the earliest supported version), is the versions table in DB version 101. This commit removes the "create all tables" statement, and instead creates the versions table in the 101 migration. See 12e074b.
CyanVoxel
left a comment
There was a problem hiding this comment.
Looks like somethings not quite right with the migrations, here I threw in a DB 9 library and it failed on migration 200:

2026-07-24 03:51:02 [info ] [Library][Migration][200] Starting DB Migration
2026-07-24 03:51:02 [info ] [Library][Migration][200] Dropping boolean_fields and value_type tables...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Adding name columns to field tables...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Dropping position columns to field tables...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Adding is_multiline column to text_fields...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Moving values from type_key columns to name...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Normalizing TextField names...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Normalizing DatetimeField names...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Updating is_multiline for legacy TEXT_BOXes...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Repairing legacy Description fields...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Repairing legacy Comment fields...
2026-07-24 03:51:02 [info ] [Library][Migration][200] Adding default field templates...
2026-07-24 03:51:02 [error ] (sqlite3.OperationalError) no such table: datetime_field_templates
[SQL: INSERT INTO datetime_field_templates (name) VALUES (?)]
[parameters: ('Date',)]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
Verified working on main
| "Couldn't update version, continuing without commit", | ||
| error=e, | ||
| ) | ||
| session.flush() |
There was a problem hiding this comment.
Why the session.flush() here?
There was a problem hiding this comment.
A fallback in case the migration doesn't flush on its own
| @@ -2160,7 +1778,8 @@ def get_version(self, key: str) -> int: | |||
| except Exception: | |||
| return 0 | |||
|
|
|||
| def set_version(self, session: Session, key: str, value: int) -> None: | |||
| @staticmethod | |||
| def _set_version(session: Session, key: str, value: int) -> None: | |||
There was a problem hiding this comment.
These should be public if they're used in DBMigrations
There was a problem hiding this comment.
I have moved _set_version to DBMigrations.__set_version as it isn't used anywhere else.
I still think it would be useful to differentiate between _ and __, where _ essentially means "private, except for a small number of exceptions". Because in this case for example I intended _get_version to only be used in the .alchemy submodule as it directly touches sql stuff (also there would be a name collision with get_version if the _ were removed). Other examples are for example when a private function needs to be used by the tests, where it doesn't make sense to make it public, but keeping it private (via __) isn't possible either.
Another advantage would that looking at a function with __ immediately tells you that it isn't used outside the class, whereas _ leaves that open.
There was a problem hiding this comment.
The reason I ended up souring on the _ and __ delineation is because in practice it became very difficult to keep up with, where I found myself constantly refactoring variable names to add or remove underscores across more and more affected files while simultaneously getting frustrated at having to type "Shift+-+-" over and over again just to start typing variable names - all for what is a superficial meaning placed onto variables for a language that doesn't actually enforce these concepts at best, and implements them differently in a way we're not respecting (i.e. name mangling) at worst.
It sounds like a good idea on paper, and believe me if Python had actual private and protected keywords I'd be all over them, but in practice the two types of prefixes is just more of a burden than they're worth imo, and a single underscore will do just fine to indicate intended private usage. If an attribute is meant to be used sometimes publicly (tests being an exception), then it should just be public - and if there are aspects of an attribute that shouldn't be allowed publicly, then those should be hidden away somehow, like a read-only getter property.
Yeah turns out the one time I didn't test, I overlooked something ^^' I forgot that adding relationships also adds tables that need to be created. |
|
|
||
|
|
||
| class DBMigration: | ||
| version: int = None # pyright: ignore[reportAssignmentType] |
There was a problem hiding this comment.
This (should) be able to just be unbound to avoid the pyright error
| version: int = None # pyright: ignore[reportAssignmentType] | |
| version: int |
| session.flush() | ||
| else: | ||
| session.commit() | ||
| logger.info(f"[Library][Migration][{migration.version}] Completed DB Migration") |
There was a problem hiding this comment.
Wouldn't this print even if the migration fails? Just a little nit pick
Summary
Progress on #1442.
Aims to complete the migrations cleanup far enough that only independence from sqlalchemy remains.
Tasks Completed