mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-05-27 17:37:39 +08:00
feat(assets): preserve insertion order on tag retrieval
The /api/assets response previously sorted tags alphabetically via
.order_by(Tag.name.asc()). That breaks the structurally meaningful
"root category first, then subpath" invariant the path-collapsing
change relies on: alphabetical sort puts a custom user tag (or even
the bare "models" root) at unpredictable positions, so positional
access like tags[1] is not reliable on local.
Cloud already preserves insertion order — its Ent WithTags() eager-
load has no explicit ORDER BY, so Postgres returns rows in physical
insertion order. Local's composite primary key on
(asset_reference_id, tag_name) means SQLite walks the index in
tag_name order even without an explicit ORDER BY, so just dropping
the clause isn't enough.
Switching to ORDER BY added_at ASC, tag_name ASC keeps the path
tags inserted via set_reference_tags in their original order
(microsecond-resolution timestamps disambiguate same-batch inserts;
tag_name is a deterministic tiebreaker for the rare collision case).
Custom tags added later via add_tags_to_reference land after the
path tags in their own added_at bucket.
Applies to both response-shaping queries:
- list_references_page (GET /api/assets, tag_map join)
- fetch_reference_asset_and_tags (GET /api/assets/{id})
Catalog/histogram queries in app/assets/database/queries/tags.py
keep their alphabetical sort — those endpoints are listing all tags,
not per-asset tags, and alphabetical is the right shape there.
This commit is contained in:
parent
a0d1238829
commit
36f9a6fdef
@ -327,7 +327,12 @@ def list_references_page(
|
||||
select(AssetReferenceTag.asset_reference_id, Tag.name)
|
||||
.join(Tag, Tag.name == AssetReferenceTag.tag_name)
|
||||
.where(AssetReferenceTag.asset_reference_id.in_(id_list))
|
||||
.order_by(AssetReferenceTag.tag_name.asc())
|
||||
# Preserve insertion order so the structural first tag (the root
|
||||
# category like "models") stays in position 0 and the path-derived
|
||||
# sub-path tag stays in position 1, matching cloud's behavior.
|
||||
# tag_name is a deterministic tiebreaker when multiple tags share
|
||||
# an added_at (same-batch insert via set_reference_tags).
|
||||
.order_by(AssetReferenceTag.added_at.asc(), AssetReferenceTag.tag_name.asc())
|
||||
)
|
||||
for ref_id, tag_name in rows.all():
|
||||
tag_map[ref_id].append(tag_name)
|
||||
@ -355,7 +360,8 @@ def fetch_reference_asset_and_tags(
|
||||
build_visible_owner_clause(owner_id),
|
||||
)
|
||||
.options(noload(AssetReference.tags))
|
||||
.order_by(Tag.name.asc())
|
||||
# See list_references_page for the rationale behind ordering by added_at.
|
||||
.order_by(AssetReferenceTag.added_at.asc(), Tag.name.asc())
|
||||
)
|
||||
|
||||
rows = session.execute(stmt).all()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user