Skip to content

Commit

Permalink
fix: patch incorrect description type & invalid disambiguation_id refs (
Browse files Browse the repository at this point in the history
#782)

* fix: update DESCRIPTION to the TEXT_BOX type

* fix: remove `disambiguation_id` refs with a tag is deleted
  • Loading branch information
CyanVoxel authored Feb 3, 2025
1 parent 6a54323 commit 480328b
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 8 deletions.
2 changes: 1 addition & 1 deletion tagstudio/src/core/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ class LibraryPrefs(DefaultEnum):
IS_EXCLUDE_LIST = True
EXTENSION_LIST: list[str] = [".json", ".xmp", ".aae"]
PAGE_SIZE: int = 500
DB_VERSION: int = 6
DB_VERSION: int = 7
2 changes: 1 addition & 1 deletion tagstudio/src/core/library/alchemy/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class _FieldID(Enum):
AUTHOR = DefaultField(id=1, name="Author", type=FieldTypeEnum.TEXT_LINE)
ARTIST = DefaultField(id=2, name="Artist", type=FieldTypeEnum.TEXT_LINE)
URL = DefaultField(id=3, name="URL", type=FieldTypeEnum.TEXT_LINE)
DESCRIPTION = DefaultField(id=4, name="Description", type=FieldTypeEnum.TEXT_LINE)
DESCRIPTION = DefaultField(id=4, name="Description", type=FieldTypeEnum.TEXT_BOX)
NOTES = DefaultField(id=5, name="Notes", type=FieldTypeEnum.TEXT_BOX)
COLLATION = DefaultField(id=9, name="Collation", type=FieldTypeEnum.TEXT_LINE)
DATE = DefaultField(id=10, name="Date", type=FieldTypeEnum.DATETIME)
Expand Down
60 changes: 54 additions & 6 deletions tagstudio/src/core/library/alchemy/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ def open_sqlite_library(self, library_dir: Path, is_new: bool) -> LibraryStatus:
# https://docs.sqlalchemy.org/en/20/changelog/migration_07.html
# Under -> sqlite-the-sqlite-dialect-now-uses-nullpool-for-file-based-databases
poolclass = None if self.storage_path == ":memory:" else NullPool
db_version: int = 0

logger.info(
"[Library] Opening SQLite Library",
Expand All @@ -328,11 +329,13 @@ def open_sqlite_library(self, library_dir: Path, is_new: bool) -> LibraryStatus:
with Session(self.engine) as session:
# dont check db version when creating new library
if not is_new:
db_version = session.scalar(
db_result = session.scalar(
select(Preferences).where(Preferences.key == LibraryPrefs.DB_VERSION.name)
)
if db_result:
db_version = db_result.value # type: ignore

if not db_version or db_version.value != LibraryPrefs.DB_VERSION.default:
if db_version < 6: # NOTE: DB_VERSION 6 is the first supported SQL DB version.
mismatch_text = Translations.translate_formatted(
"status.library_version_mismatch"
)
Expand All @@ -344,15 +347,14 @@ def open_sqlite_library(self, library_dir: Path, is_new: bool) -> LibraryStatus:
success=False,
message=(
f"{mismatch_text}\n"
f"{found_text} v{0 if not db_version else db_version.value}, "
f"{found_text} v{db_version}, "
f"{expected_text} v{LibraryPrefs.DB_VERSION.default}"
),
)

logger.info(f"[Library] DB_VERSION: {db_version}")
make_tables(self.engine)

# TODO: Determine a good way of updating built-in data after updates.

# Add default tag color namespaces.
if is_new:
namespaces = default_color_groups.namespaces()
Expand Down Expand Up @@ -421,14 +423,52 @@ def open_sqlite_library(self, library_dir: Path, is_new: bool) -> LibraryStatus:
)
session.add(folder)
session.expunge(folder)

session.commit()
self.folder = folder

# Apply any post-SQL migration patches.
if not is_new:
# NOTE: DB_VERSION 6 was first used in v9.5.0-pr1
if db_version == 6:
self.apply_db6_patches(session)
else:
pass

# Update DB_VERSION
self.set_prefs(LibraryPrefs.DB_VERSION, LibraryPrefs.DB_VERSION.default)

# everything is fine, set the library path
self.library_dir = library_dir
return LibraryStatus(success=True, library_path=library_dir)

def apply_db6_patches(self, session: Session):
"""Apply migration patches to a library with DB_VERSION 6.
DB_VERSION 6 was first used in v9.5.0-pr1.
"""
logger.info("[Library] Applying patches to DB_VERSION: 6 library...")
with session:
# Repair "Description" fields with a TEXT_LINE key instead of a TEXT_BOX key.
desc_stmd = (
update(ValueType)
.where(ValueType.key == _FieldID.DESCRIPTION.name)
.values(type=FieldTypeEnum.TEXT_BOX.name)
)
session.execute(desc_stmd)
session.flush()

# Repair tags that may have a disambiguation_id pointing towards a deleted tag.
all_tag_ids: set[int] = {tag.id for tag in self.tags}
disam_stmt = (
update(Tag)
.where(Tag.disambiguation_id.not_in(all_tag_ids))
.values(disambiguation_id=None)
)
session.execute(disam_stmt)
session.flush()

session.commit()

@property
def default_fields(self) -> list[BaseField]:
with Session(self.engine) as session:
Expand Down Expand Up @@ -793,6 +833,14 @@ def remove_tag(self, tag: Tag):
session.delete(child_tag)
session.expunge(child_tag)

disam_stmt = (
update(Tag)
.where(Tag.disambiguation_id == tag.id)
.values(disambiguation_id=None)
)
session.execute(disam_stmt)
session.flush()

session.delete(tag)
session.commit()
session.expunge(tag)
Expand Down

0 comments on commit 480328b

Please sign in to comment.