refac
This commit is contained in:
@@ -431,22 +431,31 @@ class ChatTable:
|
|||||||
def update_chat_tags_by_id(
|
def update_chat_tags_by_id(
|
||||||
self, id: str, tags: list[str], user
|
self, id: str, tags: list[str], user
|
||||||
) -> Optional[ChatModel]:
|
) -> Optional[ChatModel]:
|
||||||
chat = self.get_chat_by_id(id)
|
with get_db_context() as db:
|
||||||
if chat is None:
|
chat = db.get(Chat, id)
|
||||||
return None
|
if chat is None:
|
||||||
|
return None
|
||||||
|
|
||||||
self.delete_all_tags_by_id_and_user_id(id, user.id)
|
old_tags = chat.meta.get("tags", [])
|
||||||
|
new_tags = [t for t in tags if t.replace(" ", "_").lower() != "none"]
|
||||||
|
new_tag_ids = [t.replace(" ", "_").lower() for t in new_tags]
|
||||||
|
|
||||||
for tag in chat.meta.get("tags", []):
|
# Single meta update
|
||||||
if self.count_chats_by_tag_name_and_user_id(tag, user.id) == 0:
|
chat.meta = {**chat.meta, "tags": new_tag_ids}
|
||||||
Tags.delete_tag_by_name_and_user_id(tag, user.id)
|
db.commit()
|
||||||
|
db.refresh(chat)
|
||||||
|
|
||||||
for tag_name in tags:
|
# Batch-create any missing tag rows
|
||||||
if tag_name.lower() == "none":
|
Tags.ensure_tags_exist(new_tags, user.id, db=db)
|
||||||
continue
|
|
||||||
|
|
||||||
self.add_chat_tag_by_id_and_user_id_and_tag_name(id, user.id, tag_name)
|
# Clean up orphaned old tags in one query
|
||||||
return self.get_chat_by_id(id)
|
removed = set(old_tags) - set(new_tag_ids)
|
||||||
|
if removed:
|
||||||
|
self.delete_orphan_tags_for_user(
|
||||||
|
list(removed), user.id, db=db
|
||||||
|
)
|
||||||
|
|
||||||
|
return ChatModel.model_validate(chat)
|
||||||
|
|
||||||
def get_chat_title_by_id(self, id: str) -> Optional[str]:
|
def get_chat_title_by_id(self, id: str) -> Optional[str]:
|
||||||
chat = self.get_chat_by_id(id)
|
chat = self.get_chat_by_id(id)
|
||||||
@@ -1267,8 +1276,8 @@ class ChatTable:
|
|||||||
) -> list[TagModel]:
|
) -> list[TagModel]:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
chat = db.get(Chat, id)
|
chat = db.get(Chat, id)
|
||||||
tags = chat.meta.get("tags", [])
|
tag_ids = chat.meta.get("tags", [])
|
||||||
return [Tags.get_tag_by_name_and_user_id(tag, user_id) for tag in tags]
|
return Tags.get_tags_by_ids_and_user_id(tag_ids, user_id, db=db)
|
||||||
|
|
||||||
def get_chat_list_by_user_id_and_tag_name(
|
def get_chat_list_by_user_id_and_tag_name(
|
||||||
self,
|
self,
|
||||||
@@ -1309,20 +1318,16 @@ class ChatTable:
|
|||||||
def add_chat_tag_by_id_and_user_id_and_tag_name(
|
def add_chat_tag_by_id_and_user_id_and_tag_name(
|
||||||
self, id: str, user_id: str, tag_name: str, db: Optional[Session] = None
|
self, id: str, user_id: str, tag_name: str, db: Optional[Session] = None
|
||||||
) -> Optional[ChatModel]:
|
) -> Optional[ChatModel]:
|
||||||
tag = Tags.get_tag_by_name_and_user_id(tag_name, user_id)
|
tag_id = tag_name.replace(" ", "_").lower()
|
||||||
if tag is None:
|
Tags.ensure_tags_exist([tag_name], user_id, db=db)
|
||||||
tag = Tags.insert_new_tag(tag_name, user_id)
|
|
||||||
try:
|
try:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
chat = db.get(Chat, id)
|
chat = db.get(Chat, id)
|
||||||
|
|
||||||
tag_id = tag.id
|
|
||||||
if tag_id not in chat.meta.get("tags", []):
|
if tag_id not in chat.meta.get("tags", []):
|
||||||
chat.meta = {
|
chat.meta = {
|
||||||
**chat.meta,
|
**chat.meta,
|
||||||
"tags": list(set(chat.meta.get("tags", []) + [tag_id])),
|
"tags": list(set(chat.meta.get("tags", []) + [tag_id])),
|
||||||
}
|
}
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(chat)
|
db.refresh(chat)
|
||||||
return ChatModel.model_validate(chat)
|
return ChatModel.model_validate(chat)
|
||||||
@@ -1332,40 +1337,55 @@ class ChatTable:
|
|||||||
def count_chats_by_tag_name_and_user_id(
|
def count_chats_by_tag_name_and_user_id(
|
||||||
self, tag_name: str, user_id: str, db: Optional[Session] = None
|
self, tag_name: str, user_id: str, db: Optional[Session] = None
|
||||||
) -> int:
|
) -> int:
|
||||||
with get_db_context(db) as db: # Assuming `get_db()` returns a session object
|
with get_db_context(db) as db:
|
||||||
query = db.query(Chat).filter_by(user_id=user_id, archived=False)
|
query = db.query(Chat).filter_by(user_id=user_id, archived=False)
|
||||||
|
|
||||||
# Normalize the tag_name for consistency
|
|
||||||
tag_id = tag_name.replace(" ", "_").lower()
|
tag_id = tag_name.replace(" ", "_").lower()
|
||||||
|
|
||||||
if db.bind.dialect.name == "sqlite":
|
if db.bind.dialect.name == "sqlite":
|
||||||
# SQLite JSON1 support for querying the tags inside the `meta` JSON field
|
|
||||||
query = query.filter(
|
query = query.filter(
|
||||||
text(
|
text(
|
||||||
f"EXISTS (SELECT 1 FROM json_each(Chat.meta, '$.tags') WHERE json_each.value = :tag_id)"
|
"EXISTS (SELECT 1 FROM json_each(Chat.meta, '$.tags') WHERE json_each.value = :tag_id)"
|
||||||
)
|
)
|
||||||
).params(tag_id=tag_id)
|
).params(tag_id=tag_id)
|
||||||
|
|
||||||
elif db.bind.dialect.name == "postgresql":
|
elif db.bind.dialect.name == "postgresql":
|
||||||
# PostgreSQL JSONB support for querying the tags inside the `meta` JSON field
|
|
||||||
query = query.filter(
|
query = query.filter(
|
||||||
text(
|
text(
|
||||||
"EXISTS (SELECT 1 FROM json_array_elements_text(Chat.meta->'tags') elem WHERE elem = :tag_id)"
|
"EXISTS (SELECT 1 FROM json_array_elements_text(Chat.meta->'tags') elem WHERE elem = :tag_id)"
|
||||||
)
|
)
|
||||||
).params(tag_id=tag_id)
|
).params(tag_id=tag_id)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
f"Unsupported dialect: {db.bind.dialect.name}"
|
f"Unsupported dialect: {db.bind.dialect.name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get the count of matching records
|
return query.count()
|
||||||
count = query.count()
|
|
||||||
|
|
||||||
# Debugging output for inspection
|
def delete_orphan_tags_for_user(
|
||||||
log.info(f"Count of chats for tag '{tag_name}': {count}")
|
self,
|
||||||
|
tag_ids: list[str],
|
||||||
|
user_id: str,
|
||||||
|
threshold: int = 0,
|
||||||
|
db: Optional[Session] = None,
|
||||||
|
) -> None:
|
||||||
|
"""Delete tag rows from *tag_ids* that appear in at most *threshold*
|
||||||
|
non-archived chats for *user_id*. One query to find orphans, one to
|
||||||
|
delete them.
|
||||||
|
|
||||||
return count
|
Use threshold=0 after a tag is already removed from a chat's meta.
|
||||||
|
Use threshold=1 when the chat itself is about to be deleted (the
|
||||||
|
referencing chat still exists at query time).
|
||||||
|
"""
|
||||||
|
if not tag_ids:
|
||||||
|
return
|
||||||
|
with get_db_context(db) as db:
|
||||||
|
orphans = []
|
||||||
|
for tag_id in tag_ids:
|
||||||
|
count = self.count_chats_by_tag_name_and_user_id(
|
||||||
|
tag_id, user_id, db=db
|
||||||
|
)
|
||||||
|
if count <= threshold:
|
||||||
|
orphans.append(tag_id)
|
||||||
|
Tags.delete_tags_by_ids_and_user_id(orphans, user_id, db=db)
|
||||||
|
|
||||||
def count_chats_by_folder_id_and_user_id(
|
def count_chats_by_folder_id_and_user_id(
|
||||||
self, folder_id: str, user_id: str, db: Optional[Session] = None
|
self, folder_id: str, user_id: str, db: Optional[Session] = None
|
||||||
|
|||||||
@@ -115,5 +115,45 @@ class TagTable:
|
|||||||
log.error(f"delete_tag: {e}")
|
log.error(f"delete_tag: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def delete_tags_by_ids_and_user_id(
|
||||||
|
self, ids: list[str], user_id: str, db: Optional[Session] = None
|
||||||
|
) -> bool:
|
||||||
|
"""Delete all tags whose id is in *ids* for the given user, in one query."""
|
||||||
|
if not ids:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
with get_db_context(db) as db:
|
||||||
|
db.query(Tag).filter(
|
||||||
|
Tag.id.in_(ids), Tag.user_id == user_id
|
||||||
|
).delete(synchronize_session=False)
|
||||||
|
db.commit()
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"delete_tags_by_ids: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def ensure_tags_exist(
|
||||||
|
self, names: list[str], user_id: str, db: Optional[Session] = None
|
||||||
|
) -> None:
|
||||||
|
"""Create tag rows for any *names* that don't already exist for *user_id*."""
|
||||||
|
if not names:
|
||||||
|
return
|
||||||
|
ids = [n.replace(" ", "_").lower() for n in names]
|
||||||
|
with get_db_context(db) as db:
|
||||||
|
existing = {
|
||||||
|
t.id
|
||||||
|
for t in db.query(Tag.id)
|
||||||
|
.filter(Tag.id.in_(ids), Tag.user_id == user_id)
|
||||||
|
.all()
|
||||||
|
}
|
||||||
|
new_tags = [
|
||||||
|
Tag(id=tag_id, name=name, user_id=user_id)
|
||||||
|
for tag_id, name in zip(ids, names)
|
||||||
|
if tag_id not in existing
|
||||||
|
]
|
||||||
|
if new_tags:
|
||||||
|
db.add_all(new_tags)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
Tags = TagTable()
|
Tags = TagTable()
|
||||||
|
|||||||
@@ -1131,9 +1131,9 @@ async def delete_chat_by_id(
|
|||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
detail=ERROR_MESSAGES.NOT_FOUND,
|
detail=ERROR_MESSAGES.NOT_FOUND,
|
||||||
)
|
)
|
||||||
for tag in chat.meta.get("tags", []):
|
Chats.delete_orphan_tags_for_user(
|
||||||
if Chats.count_chats_by_tag_name_and_user_id(tag, user.id, db=db) == 1:
|
chat.meta.get("tags", []), user.id, threshold=1, db=db
|
||||||
Tags.delete_tag_by_name_and_user_id(tag, user.id, db=db)
|
)
|
||||||
|
|
||||||
result = Chats.delete_chat_by_id(id, db=db)
|
result = Chats.delete_chat_by_id(id, db=db)
|
||||||
|
|
||||||
@@ -1153,9 +1153,9 @@ async def delete_chat_by_id(
|
|||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
detail=ERROR_MESSAGES.NOT_FOUND,
|
detail=ERROR_MESSAGES.NOT_FOUND,
|
||||||
)
|
)
|
||||||
for tag in chat.meta.get("tags", []):
|
Chats.delete_orphan_tags_for_user(
|
||||||
if Chats.count_chats_by_tag_name_and_user_id(tag, user.id, db=db) == 1:
|
chat.meta.get("tags", []), user.id, threshold=1, db=db
|
||||||
Tags.delete_tag_by_name_and_user_id(tag, user.id, db=db)
|
)
|
||||||
|
|
||||||
result = Chats.delete_chat_by_id_and_user_id(id, user.id, db=db)
|
result = Chats.delete_chat_by_id_and_user_id(id, user.id, db=db)
|
||||||
return result
|
return result
|
||||||
@@ -1317,21 +1317,13 @@ async def archive_chat_by_id(
|
|||||||
if chat:
|
if chat:
|
||||||
chat = Chats.toggle_chat_archive_by_id(id, db=db)
|
chat = Chats.toggle_chat_archive_by_id(id, db=db)
|
||||||
|
|
||||||
# Delete tags if chat is archived
|
tag_ids = chat.meta.get("tags", [])
|
||||||
if chat.archived:
|
if chat.archived:
|
||||||
for tag_id in chat.meta.get("tags", []):
|
# Archived chats are excluded from count — clean up orphans
|
||||||
if (
|
Chats.delete_orphan_tags_for_user(tag_ids, user.id, db=db)
|
||||||
Chats.count_chats_by_tag_name_and_user_id(tag_id, user.id, db=db)
|
|
||||||
== 0
|
|
||||||
):
|
|
||||||
log.debug(f"deleting tag: {tag_id}")
|
|
||||||
Tags.delete_tag_by_name_and_user_id(tag_id, user.id, db=db)
|
|
||||||
else:
|
else:
|
||||||
for tag_id in chat.meta.get("tags", []):
|
# Unarchived — ensure tag rows exist
|
||||||
tag = Tags.get_tag_by_name_and_user_id(tag_id, user.id, db=db)
|
Tags.ensure_tags_exist(tag_ids, user.id, db=db)
|
||||||
if tag is None:
|
|
||||||
log.debug(f"inserting tag: {tag_id}")
|
|
||||||
tag = Tags.insert_new_tag(tag_id, user.id, db=db)
|
|
||||||
|
|
||||||
return ChatResponse(**chat.model_dump())
|
return ChatResponse(**chat.model_dump())
|
||||||
else:
|
else:
|
||||||
@@ -1537,11 +1529,9 @@ async def delete_all_tags_by_id(
|
|||||||
):
|
):
|
||||||
chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db)
|
chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db)
|
||||||
if chat:
|
if chat:
|
||||||
|
old_tags = chat.meta.get("tags", [])
|
||||||
Chats.delete_all_tags_by_id_and_user_id(id, user.id, db=db)
|
Chats.delete_all_tags_by_id_and_user_id(id, user.id, db=db)
|
||||||
|
Chats.delete_orphan_tags_for_user(old_tags, user.id, db=db)
|
||||||
for tag in chat.meta.get("tags", []):
|
|
||||||
if Chats.count_chats_by_tag_name_and_user_id(tag, user.id, db=db) == 0:
|
|
||||||
Tags.delete_tag_by_name_and_user_id(tag, user.id, db=db)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user