mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-06-12 09:17:51 +08:00
chore(assets): drop vestigial tags.tag_type column (#14248)
tag_type was always "user" in practice — no code path ever set it to anything else (no system/seeded classification was wired up) and nothing queried it. The column, its ix_tags_tag_type index, and the TagUsage.type API field were dead weight, so they're removed. Adds alembic migration 0004 to drop the column and index. Verified: asset-seeder tests pass; migration applies cleanly on a fresh SQLite (tags retains only name; tag_type column + index dropped). Co-authored-by: guill <jacob.e.segal@gmail.com>
This commit is contained in:
parent
f350acdf21
commit
a76bb4380e
39
alembic_db/versions/0004_drop_tag_type.py
Normal file
39
alembic_db/versions/0004_drop_tag_type.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
"""
|
||||||
|
Drop the vestigial tags.tag_type column.
|
||||||
|
|
||||||
|
tag_type was always "user" in practice — no code path ever set it to anything
|
||||||
|
else (no system/seeded classification was ever wired up) and nothing queried it.
|
||||||
|
The column, its index (ix_tags_tag_type), and the corresponding API field were
|
||||||
|
dead weight, so they are removed.
|
||||||
|
|
||||||
|
Revision ID: 0004_drop_tag_type
|
||||||
|
Revises: 0003_add_metadata_job_id
|
||||||
|
Create Date: 2026-06-03
|
||||||
|
"""
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
revision = "0004_drop_tag_type"
|
||||||
|
down_revision = "0003_add_metadata_job_id"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
with op.batch_alter_table("tags") as batch_op:
|
||||||
|
batch_op.drop_index("ix_tags_tag_type")
|
||||||
|
batch_op.drop_column("tag_type")
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
with op.batch_alter_table("tags") as batch_op:
|
||||||
|
batch_op.add_column(
|
||||||
|
sa.Column(
|
||||||
|
"tag_type",
|
||||||
|
sa.String(length=32),
|
||||||
|
nullable=False,
|
||||||
|
server_default="user",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
batch_op.create_index("ix_tags_tag_type", ["tag_type"])
|
||||||
@ -575,8 +575,8 @@ async def get_tags(request: web.Request) -> web.Response:
|
|||||||
)
|
)
|
||||||
|
|
||||||
tags = [
|
tags = [
|
||||||
schemas_out.TagUsage(name=name, count=count, type=tag_type)
|
schemas_out.TagUsage(name=name, count=count)
|
||||||
for (name, tag_type, count) in rows
|
for (name, count) in rows
|
||||||
]
|
]
|
||||||
payload = schemas_out.TagsList(
|
payload = schemas_out.TagsList(
|
||||||
tags=tags, total=total, has_more=(query.offset + len(tags)) < total
|
tags=tags, total=total, has_more=(query.offset + len(tags)) < total
|
||||||
|
|||||||
@ -46,7 +46,6 @@ class AssetsList(BaseModel):
|
|||||||
class TagUsage(BaseModel):
|
class TagUsage(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
count: int
|
count: int
|
||||||
type: str
|
|
||||||
|
|
||||||
|
|
||||||
class TagsList(BaseModel):
|
class TagsList(BaseModel):
|
||||||
|
|||||||
@ -227,7 +227,6 @@ class Tag(Base):
|
|||||||
__tablename__ = "tags"
|
__tablename__ = "tags"
|
||||||
|
|
||||||
name: Mapped[str] = mapped_column(String(512), primary_key=True)
|
name: Mapped[str] = mapped_column(String(512), primary_key=True)
|
||||||
tag_type: Mapped[str] = mapped_column(String(32), nullable=False, default="user")
|
|
||||||
|
|
||||||
asset_reference_links: Mapped[list[AssetReferenceTag]] = relationship(
|
asset_reference_links: Mapped[list[AssetReferenceTag]] = relationship(
|
||||||
back_populates="tag",
|
back_populates="tag",
|
||||||
@ -240,7 +239,5 @@ class Tag(Base):
|
|||||||
overlaps="asset_reference_links,tag_links,tags,asset_reference",
|
overlaps="asset_reference_links,tag_links,tags,asset_reference",
|
||||||
)
|
)
|
||||||
|
|
||||||
__table_args__ = (Index("ix_tags_tag_type", "tag_type"),)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Tag {self.name}>"
|
return f"<Tag {self.name}>"
|
||||||
|
|||||||
@ -55,13 +55,11 @@ def validate_tags_exist(session: Session, tags: list[str]) -> None:
|
|||||||
raise ValueError(f"Unknown tags: {missing}")
|
raise ValueError(f"Unknown tags: {missing}")
|
||||||
|
|
||||||
|
|
||||||
def ensure_tags_exist(
|
def ensure_tags_exist(session: Session, names: Iterable[str]) -> None:
|
||||||
session: Session, names: Iterable[str], tag_type: str = "user"
|
|
||||||
) -> None:
|
|
||||||
wanted = normalize_tags(list(names))
|
wanted = normalize_tags(list(names))
|
||||||
if not wanted:
|
if not wanted:
|
||||||
return
|
return
|
||||||
rows = [{"name": n, "tag_type": tag_type} for n in list(dict.fromkeys(wanted))]
|
rows = [{"name": n} for n in list(dict.fromkeys(wanted))]
|
||||||
ins = (
|
ins = (
|
||||||
sqlite.insert(Tag)
|
sqlite.insert(Tag)
|
||||||
.values(rows)
|
.values(rows)
|
||||||
@ -97,7 +95,7 @@ def set_reference_tags(
|
|||||||
to_remove = [t for t in current if t not in desired]
|
to_remove = [t for t in current if t not in desired]
|
||||||
|
|
||||||
if to_add:
|
if to_add:
|
||||||
ensure_tags_exist(session, to_add, tag_type="user")
|
ensure_tags_exist(session, to_add)
|
||||||
session.add_all(
|
session.add_all(
|
||||||
[
|
[
|
||||||
AssetReferenceTag(
|
AssetReferenceTag(
|
||||||
@ -142,7 +140,7 @@ def add_tags_to_reference(
|
|||||||
return AddTagsResult(added=[], already_present=[], total_tags=total)
|
return AddTagsResult(added=[], already_present=[], total_tags=total)
|
||||||
|
|
||||||
if create_if_missing:
|
if create_if_missing:
|
||||||
ensure_tags_exist(session, norm, tag_type="user")
|
ensure_tags_exist(session, norm)
|
||||||
|
|
||||||
current = set(get_reference_tags(session, reference_id))
|
current = set(get_reference_tags(session, reference_id))
|
||||||
|
|
||||||
@ -289,7 +287,6 @@ def list_tags_with_usage(
|
|||||||
q = (
|
q = (
|
||||||
select(
|
select(
|
||||||
Tag.name,
|
Tag.name,
|
||||||
Tag.tag_type,
|
|
||||||
func.coalesce(counts_sq.c.cnt, 0).label("count"),
|
func.coalesce(counts_sq.c.cnt, 0).label("count"),
|
||||||
)
|
)
|
||||||
.select_from(Tag)
|
.select_from(Tag)
|
||||||
@ -331,7 +328,7 @@ def list_tags_with_usage(
|
|||||||
rows = (session.execute(q.limit(limit).offset(offset))).all()
|
rows = (session.execute(q.limit(limit).offset(offset))).all()
|
||||||
total = (session.execute(total_q)).scalar_one()
|
total = (session.execute(total_q)).scalar_one()
|
||||||
|
|
||||||
rows_norm = [(name, ttype, int(count or 0)) for (name, ttype, count) in rows]
|
rows_norm = [(name, int(count or 0)) for (name, count) in rows]
|
||||||
return rows_norm, int(total or 0)
|
return rows_norm, int(total or 0)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -355,7 +355,7 @@ def insert_asset_specs(specs: list[SeedAssetSpec], tag_pool: set[str]) -> int:
|
|||||||
return 0
|
return 0
|
||||||
with create_session() as sess:
|
with create_session() as sess:
|
||||||
if tag_pool:
|
if tag_pool:
|
||||||
ensure_tags_exist(sess, tag_pool, tag_type="user")
|
ensure_tags_exist(sess, tag_pool)
|
||||||
result = batch_insert_seed_assets(sess, specs=specs, owner_id="")
|
result = batch_insert_seed_assets(sess, specs=specs, owner_id="")
|
||||||
sess.commit()
|
sess.commit()
|
||||||
return result.inserted_refs
|
return result.inserted_refs
|
||||||
|
|||||||
@ -56,7 +56,6 @@ class IngestResult:
|
|||||||
|
|
||||||
class TagUsage(NamedTuple):
|
class TagUsage(NamedTuple):
|
||||||
name: str
|
name: str
|
||||||
tag_type: str
|
|
||||||
count: int
|
count: int
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -75,7 +75,7 @@ def list_tags(
|
|||||||
owner_id=owner_id,
|
owner_id=owner_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
return [TagUsage(name, tag_type, count) for name, tag_type, count in rows], total
|
return [TagUsage(name, count) for name, count in rows], total
|
||||||
|
|
||||||
|
|
||||||
def list_tag_histogram(
|
def list_tag_histogram(
|
||||||
|
|||||||
@ -40,15 +40,15 @@ def _make_reference(session: Session, asset: Asset, name: str = "test", owner_id
|
|||||||
|
|
||||||
class TestEnsureTagsExist:
|
class TestEnsureTagsExist:
|
||||||
def test_creates_new_tags(self, session: Session):
|
def test_creates_new_tags(self, session: Session):
|
||||||
ensure_tags_exist(session, ["alpha", "beta"], tag_type="user")
|
ensure_tags_exist(session, ["alpha", "beta"])
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
tags = session.query(Tag).all()
|
tags = session.query(Tag).all()
|
||||||
assert {t.name for t in tags} == {"alpha", "beta"}
|
assert {t.name for t in tags} == {"alpha", "beta"}
|
||||||
|
|
||||||
def test_is_idempotent(self, session: Session):
|
def test_is_idempotent(self, session: Session):
|
||||||
ensure_tags_exist(session, ["alpha"], tag_type="user")
|
ensure_tags_exist(session, ["alpha"])
|
||||||
ensure_tags_exist(session, ["alpha"], tag_type="user")
|
ensure_tags_exist(session, ["alpha"])
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
assert session.query(Tag).count() == 1
|
assert session.query(Tag).count() == 1
|
||||||
@ -65,13 +65,6 @@ class TestEnsureTagsExist:
|
|||||||
session.commit()
|
session.commit()
|
||||||
assert session.query(Tag).count() == 0
|
assert session.query(Tag).count() == 0
|
||||||
|
|
||||||
def test_tag_type_is_set(self, session: Session):
|
|
||||||
ensure_tags_exist(session, ["system-tag"], tag_type="system")
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
tag = session.query(Tag).filter_by(name="system-tag").one()
|
|
||||||
assert tag.tag_type == "system"
|
|
||||||
|
|
||||||
|
|
||||||
class TestGetReferenceTags:
|
class TestGetReferenceTags:
|
||||||
def test_returns_empty_for_no_tags(self, session: Session):
|
def test_returns_empty_for_no_tags(self, session: Session):
|
||||||
@ -193,7 +186,7 @@ class TestMissingTagFunctions:
|
|||||||
def test_add_missing_tag_for_asset_id(self, session: Session):
|
def test_add_missing_tag_for_asset_id(self, session: Session):
|
||||||
asset = _make_asset(session, "hash1")
|
asset = _make_asset(session, "hash1")
|
||||||
ref = _make_reference(session, asset)
|
ref = _make_reference(session, asset)
|
||||||
ensure_tags_exist(session, ["missing"], tag_type="system")
|
ensure_tags_exist(session, ["missing"])
|
||||||
|
|
||||||
add_missing_tag_for_asset_id(session, asset_id=asset.id)
|
add_missing_tag_for_asset_id(session, asset_id=asset.id)
|
||||||
session.commit()
|
session.commit()
|
||||||
@ -204,7 +197,7 @@ class TestMissingTagFunctions:
|
|||||||
def test_add_missing_tag_is_idempotent(self, session: Session):
|
def test_add_missing_tag_is_idempotent(self, session: Session):
|
||||||
asset = _make_asset(session, "hash1")
|
asset = _make_asset(session, "hash1")
|
||||||
ref = _make_reference(session, asset)
|
ref = _make_reference(session, asset)
|
||||||
ensure_tags_exist(session, ["missing"], tag_type="system")
|
ensure_tags_exist(session, ["missing"])
|
||||||
|
|
||||||
add_missing_tag_for_asset_id(session, asset_id=asset.id)
|
add_missing_tag_for_asset_id(session, asset_id=asset.id)
|
||||||
add_missing_tag_for_asset_id(session, asset_id=asset.id)
|
add_missing_tag_for_asset_id(session, asset_id=asset.id)
|
||||||
@ -216,7 +209,7 @@ class TestMissingTagFunctions:
|
|||||||
def test_remove_missing_tag_for_asset_id(self, session: Session):
|
def test_remove_missing_tag_for_asset_id(self, session: Session):
|
||||||
asset = _make_asset(session, "hash1")
|
asset = _make_asset(session, "hash1")
|
||||||
ref = _make_reference(session, asset)
|
ref = _make_reference(session, asset)
|
||||||
ensure_tags_exist(session, ["missing"], tag_type="system")
|
ensure_tags_exist(session, ["missing"])
|
||||||
add_missing_tag_for_asset_id(session, asset_id=asset.id)
|
add_missing_tag_for_asset_id(session, asset_id=asset.id)
|
||||||
|
|
||||||
remove_missing_tag_for_asset_id(session, asset_id=asset.id)
|
remove_missing_tag_for_asset_id(session, asset_id=asset.id)
|
||||||
@ -237,7 +230,7 @@ class TestListTagsWithUsage:
|
|||||||
|
|
||||||
rows, total = list_tags_with_usage(session)
|
rows, total = list_tags_with_usage(session)
|
||||||
|
|
||||||
tag_dict = {name: count for name, _, count in rows}
|
tag_dict = {name: count for name, count in rows}
|
||||||
assert tag_dict["used"] == 1
|
assert tag_dict["used"] == 1
|
||||||
assert tag_dict["unused"] == 0
|
assert tag_dict["unused"] == 0
|
||||||
assert total == 2
|
assert total == 2
|
||||||
@ -252,7 +245,7 @@ class TestListTagsWithUsage:
|
|||||||
|
|
||||||
rows, total = list_tags_with_usage(session, include_zero=False)
|
rows, total = list_tags_with_usage(session, include_zero=False)
|
||||||
|
|
||||||
tag_names = {name for name, _, _ in rows}
|
tag_names = {name for name, _ in rows}
|
||||||
assert "used" in tag_names
|
assert "used" in tag_names
|
||||||
assert "unused" not in tag_names
|
assert "unused" not in tag_names
|
||||||
|
|
||||||
@ -262,7 +255,7 @@ class TestListTagsWithUsage:
|
|||||||
|
|
||||||
rows, total = list_tags_with_usage(session, prefix="alph")
|
rows, total = list_tags_with_usage(session, prefix="alph")
|
||||||
|
|
||||||
tag_names = {name for name, _, _ in rows}
|
tag_names = {name for name, _ in rows}
|
||||||
assert tag_names == {"alpha", "alphabet"}
|
assert tag_names == {"alpha", "alphabet"}
|
||||||
|
|
||||||
def test_order_by_name(self, session: Session):
|
def test_order_by_name(self, session: Session):
|
||||||
@ -271,7 +264,7 @@ class TestListTagsWithUsage:
|
|||||||
|
|
||||||
rows, _ = list_tags_with_usage(session, order="name_asc")
|
rows, _ = list_tags_with_usage(session, order="name_asc")
|
||||||
|
|
||||||
names = [name for name, _, _ in rows]
|
names = [name for name, _ in rows]
|
||||||
assert names == ["alpha", "middle", "zebra"]
|
assert names == ["alpha", "middle", "zebra"]
|
||||||
|
|
||||||
def test_owner_visibility(self, session: Session):
|
def test_owner_visibility(self, session: Session):
|
||||||
@ -287,13 +280,13 @@ class TestListTagsWithUsage:
|
|||||||
|
|
||||||
# Empty owner sees only shared
|
# Empty owner sees only shared
|
||||||
rows, _ = list_tags_with_usage(session, owner_id="", include_zero=False)
|
rows, _ = list_tags_with_usage(session, owner_id="", include_zero=False)
|
||||||
tag_dict = {name: count for name, _, count in rows}
|
tag_dict = {name: count for name, count in rows}
|
||||||
assert tag_dict.get("shared-tag", 0) == 1
|
assert tag_dict.get("shared-tag", 0) == 1
|
||||||
assert tag_dict.get("owner-tag", 0) == 0
|
assert tag_dict.get("owner-tag", 0) == 0
|
||||||
|
|
||||||
# User1 sees both
|
# User1 sees both
|
||||||
rows, _ = list_tags_with_usage(session, owner_id="user1", include_zero=False)
|
rows, _ = list_tags_with_usage(session, owner_id="user1", include_zero=False)
|
||||||
tag_dict = {name: count for name, _, count in rows}
|
tag_dict = {name: count for name, count in rows}
|
||||||
assert tag_dict.get("shared-tag", 0) == 1
|
assert tag_dict.get("shared-tag", 0) == 1
|
||||||
assert tag_dict.get("owner-tag", 0) == 1
|
assert tag_dict.get("owner-tag", 0) == 1
|
||||||
|
|
||||||
|
|||||||
@ -141,7 +141,7 @@ class TestListTags:
|
|||||||
|
|
||||||
rows, total = list_tags()
|
rows, total = list_tags()
|
||||||
|
|
||||||
tag_dict = {name: count for name, _, count in rows}
|
tag_dict = {name: count for name, count in rows}
|
||||||
assert tag_dict["used"] == 1
|
assert tag_dict["used"] == 1
|
||||||
assert tag_dict["unused"] == 0
|
assert tag_dict["unused"] == 0
|
||||||
assert total == 2
|
assert total == 2
|
||||||
@ -155,7 +155,7 @@ class TestListTags:
|
|||||||
|
|
||||||
rows, total = list_tags(include_zero=False)
|
rows, total = list_tags(include_zero=False)
|
||||||
|
|
||||||
tag_names = {name for name, _, _ in rows}
|
tag_names = {name for name, _ in rows}
|
||||||
assert "used" in tag_names
|
assert "used" in tag_names
|
||||||
assert "unused" not in tag_names
|
assert "unused" not in tag_names
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ class TestListTags:
|
|||||||
|
|
||||||
rows, _ = list_tags(prefix="alph")
|
rows, _ = list_tags(prefix="alph")
|
||||||
|
|
||||||
tag_names = {name for name, _, _ in rows}
|
tag_names = {name for name, _ in rows}
|
||||||
assert tag_names == {"alpha", "alphabet"}
|
assert tag_names == {"alpha", "alphabet"}
|
||||||
|
|
||||||
def test_order_by_name(self, mock_create_session, session: Session):
|
def test_order_by_name(self, mock_create_session, session: Session):
|
||||||
@ -174,7 +174,7 @@ class TestListTags:
|
|||||||
|
|
||||||
rows, _ = list_tags(order="name_asc")
|
rows, _ = list_tags(order="name_asc")
|
||||||
|
|
||||||
names = [name for name, _, _ in rows]
|
names = [name for name, _ in rows]
|
||||||
assert names == ["alpha", "middle", "zebra"]
|
assert names == ["alpha", "middle", "zebra"]
|
||||||
|
|
||||||
def test_pagination(self, mock_create_session, session: Session):
|
def test_pagination(self, mock_create_session, session: Session):
|
||||||
@ -185,7 +185,7 @@ class TestListTags:
|
|||||||
|
|
||||||
assert total == 5
|
assert total == 5
|
||||||
assert len(rows) == 2
|
assert len(rows) == 2
|
||||||
names = [name for name, _, _ in rows]
|
names = [name for name, _ in rows]
|
||||||
assert names == ["b", "c"]
|
assert names == ["b", "c"]
|
||||||
|
|
||||||
def test_clamps_limit(self, mock_create_session, session: Session):
|
def test_clamps_limit(self, mock_create_session, session: Session):
|
||||||
|
|||||||
@ -95,7 +95,7 @@ def _make_asset(
|
|||||||
def _ensure_missing_tag(session: Session):
|
def _ensure_missing_tag(session: Session):
|
||||||
"""Ensure the 'missing' tag exists."""
|
"""Ensure the 'missing' tag exists."""
|
||||||
if not session.get(Tag, "missing"):
|
if not session.get(Tag, "missing"):
|
||||||
session.add(Tag(name="missing", tag_type="system"))
|
session.add(Tag(name="missing"))
|
||||||
session.flush()
|
session.flush()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user