mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-12-17 18:13:01 +08:00
use UUID instead of autoincrement Integer for Assets ID field
This commit is contained in:
parent
bdf4ba24ce
commit
6b86be320a
@ -30,7 +30,7 @@ def upgrade() -> None:
|
|||||||
# ASSETS_INFO: user-visible references (mutable metadata)
|
# ASSETS_INFO: user-visible references (mutable metadata)
|
||||||
op.create_table(
|
op.create_table(
|
||||||
"assets_info",
|
"assets_info",
|
||||||
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
sa.Column("id", sa.String(length=36), primary_key=True),
|
||||||
sa.Column("owner_id", sa.String(length=128), nullable=False, server_default=""),
|
sa.Column("owner_id", sa.String(length=128), nullable=False, server_default=""),
|
||||||
sa.Column("name", sa.String(length=512), nullable=False),
|
sa.Column("name", sa.String(length=512), nullable=False),
|
||||||
sa.Column("asset_hash", sa.String(length=256), sa.ForeignKey("assets.hash", ondelete="RESTRICT"), nullable=False),
|
sa.Column("asset_hash", sa.String(length=256), sa.ForeignKey("assets.hash", ondelete="RESTRICT"), nullable=False),
|
||||||
@ -40,7 +40,6 @@ def upgrade() -> None:
|
|||||||
sa.Column("updated_at", sa.DateTime(timezone=False), nullable=False),
|
sa.Column("updated_at", sa.DateTime(timezone=False), nullable=False),
|
||||||
sa.Column("last_access_time", sa.DateTime(timezone=False), nullable=False),
|
sa.Column("last_access_time", sa.DateTime(timezone=False), nullable=False),
|
||||||
sa.UniqueConstraint("asset_hash", "owner_id", "name", name="uq_assets_info_hash_owner_name"),
|
sa.UniqueConstraint("asset_hash", "owner_id", "name", name="uq_assets_info_hash_owner_name"),
|
||||||
sqlite_autoincrement=True,
|
|
||||||
)
|
)
|
||||||
op.create_index("ix_assets_info_owner_id", "assets_info", ["owner_id"])
|
op.create_index("ix_assets_info_owner_id", "assets_info", ["owner_id"])
|
||||||
op.create_index("ix_assets_info_asset_hash", "assets_info", ["asset_hash"])
|
op.create_index("ix_assets_info_asset_hash", "assets_info", ["asset_hash"])
|
||||||
@ -61,7 +60,7 @@ def upgrade() -> None:
|
|||||||
# ASSET_INFO_TAGS: many-to-many for tags on AssetInfo
|
# ASSET_INFO_TAGS: many-to-many for tags on AssetInfo
|
||||||
op.create_table(
|
op.create_table(
|
||||||
"asset_info_tags",
|
"asset_info_tags",
|
||||||
sa.Column("asset_info_id", sa.Integer(), sa.ForeignKey("assets_info.id", ondelete="CASCADE"), nullable=False),
|
sa.Column("asset_info_id", sa.String(length=36), sa.ForeignKey("assets_info.id", ondelete="CASCADE"), nullable=False),
|
||||||
sa.Column("tag_name", sa.String(length=512), sa.ForeignKey("tags.name", ondelete="RESTRICT"), nullable=False),
|
sa.Column("tag_name", sa.String(length=512), sa.ForeignKey("tags.name", ondelete="RESTRICT"), nullable=False),
|
||||||
sa.Column("origin", sa.String(length=32), nullable=False, server_default="manual"),
|
sa.Column("origin", sa.String(length=32), nullable=False, server_default="manual"),
|
||||||
sa.Column("added_at", sa.DateTime(timezone=False), nullable=False),
|
sa.Column("added_at", sa.DateTime(timezone=False), nullable=False),
|
||||||
@ -83,7 +82,7 @@ def upgrade() -> None:
|
|||||||
# ASSET_INFO_META: typed KV projection of user_metadata for filtering/sorting
|
# ASSET_INFO_META: typed KV projection of user_metadata for filtering/sorting
|
||||||
op.create_table(
|
op.create_table(
|
||||||
"asset_info_meta",
|
"asset_info_meta",
|
||||||
sa.Column("asset_info_id", sa.Integer(), sa.ForeignKey("assets_info.id", ondelete="CASCADE"), nullable=False),
|
sa.Column("asset_info_id", sa.String(length=36), sa.ForeignKey("assets_info.id", ondelete="CASCADE"), nullable=False),
|
||||||
sa.Column("key", sa.String(length=256), nullable=False),
|
sa.Column("key", sa.String(length=256), nullable=False),
|
||||||
sa.Column("ordinal", sa.Integer(), nullable=False, server_default="0"),
|
sa.Column("ordinal", sa.Integer(), nullable=False, server_default="0"),
|
||||||
sa.Column("val_str", sa.String(length=2048), nullable=True),
|
sa.Column("val_str", sa.String(length=2048), nullable=True),
|
||||||
|
|||||||
@ -16,6 +16,9 @@ from . import schemas_in, schemas_out
|
|||||||
ROUTES = web.RouteTableDef()
|
ROUTES = web.RouteTableDef()
|
||||||
UserManager: Optional[user_manager.UserManager] = None
|
UserManager: Optional[user_manager.UserManager] = None
|
||||||
|
|
||||||
|
# UUID regex (canonical hyphenated form, case-insensitive)
|
||||||
|
UUID_RE = r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
|
||||||
|
|
||||||
|
|
||||||
@ROUTES.head("/api/assets/hash/{hash}")
|
@ROUTES.head("/api/assets/hash/{hash}")
|
||||||
async def head_asset_by_hash(request: web.Request) -> web.Response:
|
async def head_asset_by_hash(request: web.Request) -> web.Response:
|
||||||
@ -52,13 +55,13 @@ async def list_assets(request: web.Request) -> web.Response:
|
|||||||
return web.json_response(payload.model_dump(mode="json"))
|
return web.json_response(payload.model_dump(mode="json"))
|
||||||
|
|
||||||
|
|
||||||
@ROUTES.get("/api/assets/{id:\\d+}/content")
|
@ROUTES.get(f"/api/assets/{{id:{UUID_RE}}}/content")
|
||||||
async def download_asset_content(request: web.Request) -> web.Response:
|
async def download_asset_content(request: web.Request) -> web.Response:
|
||||||
asset_info_id_raw = request.match_info.get("id")
|
asset_info_id_raw = request.match_info.get("id", "")
|
||||||
try:
|
try:
|
||||||
asset_info_id = int(asset_info_id_raw)
|
asset_info_id = str(uuid.UUID(asset_info_id_raw))
|
||||||
except Exception:
|
except Exception:
|
||||||
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid integer.")
|
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid UUID.")
|
||||||
|
|
||||||
disposition = request.query.get("disposition", "attachment").lower().strip()
|
disposition = request.query.get("disposition", "attachment").lower().strip()
|
||||||
if disposition not in {"inline", "attachment"}:
|
if disposition not in {"inline", "attachment"}:
|
||||||
@ -282,13 +285,13 @@ async def upload_asset(request: web.Request) -> web.Response:
|
|||||||
return _error_response(500, "INTERNAL", "Unexpected server error.")
|
return _error_response(500, "INTERNAL", "Unexpected server error.")
|
||||||
|
|
||||||
|
|
||||||
@ROUTES.get("/api/assets/{id:\\d+}")
|
@ROUTES.get(f"/api/assets/{{id:{UUID_RE}}}")
|
||||||
async def get_asset(request: web.Request) -> web.Response:
|
async def get_asset(request: web.Request) -> web.Response:
|
||||||
asset_info_id_raw = request.match_info.get("id")
|
asset_info_id_raw = request.match_info.get("id", "")
|
||||||
try:
|
try:
|
||||||
asset_info_id = int(asset_info_id_raw)
|
asset_info_id = str(uuid.UUID(asset_info_id_raw))
|
||||||
except Exception:
|
except Exception:
|
||||||
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid integer.")
|
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid UUID.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = await assets_manager.get_asset(
|
result = await assets_manager.get_asset(
|
||||||
@ -302,13 +305,13 @@ async def get_asset(request: web.Request) -> web.Response:
|
|||||||
return web.json_response(result.model_dump(mode="json"), status=200)
|
return web.json_response(result.model_dump(mode="json"), status=200)
|
||||||
|
|
||||||
|
|
||||||
@ROUTES.put("/api/assets/{id:\\d+}")
|
@ROUTES.put(f"/api/assets/{{id:{UUID_RE}}}")
|
||||||
async def update_asset(request: web.Request) -> web.Response:
|
async def update_asset(request: web.Request) -> web.Response:
|
||||||
asset_info_id_raw = request.match_info.get("id")
|
asset_info_id_raw = request.match_info.get("id", "")
|
||||||
try:
|
try:
|
||||||
asset_info_id = int(asset_info_id_raw)
|
asset_info_id = str(uuid.UUID(asset_info_id_raw))
|
||||||
except Exception:
|
except Exception:
|
||||||
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid integer.")
|
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid UUID.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
body = schemas_in.UpdateAssetBody.model_validate(await request.json())
|
body = schemas_in.UpdateAssetBody.model_validate(await request.json())
|
||||||
@ -332,13 +335,13 @@ async def update_asset(request: web.Request) -> web.Response:
|
|||||||
return web.json_response(result.model_dump(mode="json"), status=200)
|
return web.json_response(result.model_dump(mode="json"), status=200)
|
||||||
|
|
||||||
|
|
||||||
@ROUTES.delete("/api/assets/{id:\\d+}")
|
@ROUTES.delete(f"/api/assets/{{id:{UUID_RE}}}")
|
||||||
async def delete_asset(request: web.Request) -> web.Response:
|
async def delete_asset(request: web.Request) -> web.Response:
|
||||||
asset_info_id_raw = request.match_info.get("id")
|
asset_info_id_raw = request.match_info.get("id", "")
|
||||||
try:
|
try:
|
||||||
asset_info_id = int(asset_info_id_raw)
|
asset_info_id = str(uuid.UUID(asset_info_id_raw))
|
||||||
except Exception:
|
except Exception:
|
||||||
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid integer.")
|
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid UUID.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
deleted = await assets_manager.delete_asset_reference(
|
deleted = await assets_manager.delete_asset_reference(
|
||||||
@ -376,13 +379,13 @@ async def get_tags(request: web.Request) -> web.Response:
|
|||||||
return web.json_response(result.model_dump(mode="json"))
|
return web.json_response(result.model_dump(mode="json"))
|
||||||
|
|
||||||
|
|
||||||
@ROUTES.post("/api/assets/{id:\\d+}/tags")
|
@ROUTES.post(f"/api/assets/{{id:{UUID_RE}}}/tags")
|
||||||
async def add_asset_tags(request: web.Request) -> web.Response:
|
async def add_asset_tags(request: web.Request) -> web.Response:
|
||||||
asset_info_id_raw = request.match_info.get("id")
|
asset_info_id_raw = request.match_info.get("id", "")
|
||||||
try:
|
try:
|
||||||
asset_info_id = int(asset_info_id_raw)
|
asset_info_id = str(uuid.UUID(asset_info_id_raw))
|
||||||
except Exception:
|
except Exception:
|
||||||
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid integer.")
|
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid UUID.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
payload = await request.json()
|
payload = await request.json()
|
||||||
@ -407,13 +410,13 @@ async def add_asset_tags(request: web.Request) -> web.Response:
|
|||||||
return web.json_response(result.model_dump(mode="json"), status=200)
|
return web.json_response(result.model_dump(mode="json"), status=200)
|
||||||
|
|
||||||
|
|
||||||
@ROUTES.delete("/api/assets/{id:\\d+}/tags")
|
@ROUTES.delete(f"/api/assets/{{id:{UUID_RE}}}/tags")
|
||||||
async def delete_asset_tags(request: web.Request) -> web.Response:
|
async def delete_asset_tags(request: web.Request) -> web.Response:
|
||||||
asset_info_id_raw = request.match_info.get("id")
|
asset_info_id_raw = request.match_info.get("id", "")
|
||||||
try:
|
try:
|
||||||
asset_info_id = int(asset_info_id_raw)
|
asset_info_id = str(uuid.UUID(asset_info_id_raw))
|
||||||
except Exception:
|
except Exception:
|
||||||
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid integer.")
|
return _error_response(400, "INVALID_ID", f"AssetInfo id '{asset_info_id_raw}' is not a valid UUID.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
payload = await request.json()
|
payload = await request.json()
|
||||||
|
|||||||
@ -4,7 +4,7 @@ from pydantic import BaseModel, ConfigDict, Field, field_serializer
|
|||||||
|
|
||||||
|
|
||||||
class AssetSummary(BaseModel):
|
class AssetSummary(BaseModel):
|
||||||
id: int
|
id: str
|
||||||
name: str
|
name: str
|
||||||
asset_hash: str
|
asset_hash: str
|
||||||
size: Optional[int] = None
|
size: Optional[int] = None
|
||||||
@ -29,7 +29,7 @@ class AssetsList(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class AssetUpdated(BaseModel):
|
class AssetUpdated(BaseModel):
|
||||||
id: int
|
id: str
|
||||||
name: str
|
name: str
|
||||||
asset_hash: str
|
asset_hash: str
|
||||||
tags: list[str] = Field(default_factory=list)
|
tags: list[str] = Field(default_factory=list)
|
||||||
@ -44,7 +44,7 @@ class AssetUpdated(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class AssetDetail(BaseModel):
|
class AssetDetail(BaseModel):
|
||||||
id: int
|
id: str
|
||||||
name: str
|
name: str
|
||||||
asset_hash: str
|
asset_hash: str
|
||||||
size: Optional[int] = None
|
size: Optional[int] = None
|
||||||
|
|||||||
@ -73,7 +73,7 @@ async def add_local_asset(tags: list[str], file_name: str, file_path: str) -> No
|
|||||||
|
|
||||||
async with await create_session() as session:
|
async with await create_session() as session:
|
||||||
if await check_fs_asset_exists_quick(session, file_path=abs_path, size_bytes=size_bytes, mtime_ns=mtime_ns):
|
if await check_fs_asset_exists_quick(session, file_path=abs_path, size_bytes=size_bytes, mtime_ns=mtime_ns):
|
||||||
await touch_asset_infos_by_fs_path(session, abs_path=abs_path)
|
await touch_asset_infos_by_fs_path(session, file_path=abs_path)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ async def list_assets(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def get_asset(*, asset_info_id: int, owner_id: str = "") -> schemas_out.AssetDetail:
|
async def get_asset(*, asset_info_id: str, owner_id: str = "") -> schemas_out.AssetDetail:
|
||||||
async with await create_session() as session:
|
async with await create_session() as session:
|
||||||
res = await fetch_asset_info_asset_and_tags(session, asset_info_id=asset_info_id, owner_id=owner_id)
|
res = await fetch_asset_info_asset_and_tags(session, asset_info_id=asset_info_id, owner_id=owner_id)
|
||||||
if not res:
|
if not res:
|
||||||
@ -172,7 +172,7 @@ async def get_asset(*, asset_info_id: int, owner_id: str = "") -> schemas_out.As
|
|||||||
|
|
||||||
async def resolve_asset_content_for_download(
|
async def resolve_asset_content_for_download(
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
owner_id: str = "",
|
owner_id: str = "",
|
||||||
) -> tuple[str, str, str]:
|
) -> tuple[str, str, str]:
|
||||||
"""
|
"""
|
||||||
@ -311,7 +311,7 @@ async def upload_asset_from_temp_path(
|
|||||||
if not info_id:
|
if not info_id:
|
||||||
raise RuntimeError("failed to create asset metadata")
|
raise RuntimeError("failed to create asset metadata")
|
||||||
|
|
||||||
pair = await fetch_asset_info_and_asset(session, asset_info_id=int(info_id), owner_id=owner_id)
|
pair = await fetch_asset_info_and_asset(session, asset_info_id=info_id, owner_id=owner_id)
|
||||||
if not pair:
|
if not pair:
|
||||||
raise RuntimeError("inconsistent DB state after ingest")
|
raise RuntimeError("inconsistent DB state after ingest")
|
||||||
info, asset = pair
|
info, asset = pair
|
||||||
@ -335,7 +335,7 @@ async def upload_asset_from_temp_path(
|
|||||||
|
|
||||||
async def update_asset(
|
async def update_asset(
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
tags: Optional[list[str]] = None,
|
tags: Optional[list[str]] = None,
|
||||||
user_metadata: Optional[dict] = None,
|
user_metadata: Optional[dict] = None,
|
||||||
@ -371,7 +371,7 @@ async def update_asset(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def delete_asset_reference(*, asset_info_id: int, owner_id: str) -> bool:
|
async def delete_asset_reference(*, asset_info_id: str, owner_id: str) -> bool:
|
||||||
async with await create_session() as session:
|
async with await create_session() as session:
|
||||||
r = await delete_asset_info_by_id(session, asset_info_id=asset_info_id, owner_id=owner_id)
|
r = await delete_asset_info_by_id(session, asset_info_id=asset_info_id, owner_id=owner_id)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
@ -448,7 +448,7 @@ async def list_tags(
|
|||||||
|
|
||||||
async def add_tags_to_asset(
|
async def add_tags_to_asset(
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
tags: list[str],
|
tags: list[str],
|
||||||
origin: str = "manual",
|
origin: str = "manual",
|
||||||
owner_id: str = "",
|
owner_id: str = "",
|
||||||
@ -473,7 +473,7 @@ async def add_tags_to_asset(
|
|||||||
|
|
||||||
async def remove_tags_from_asset(
|
async def remove_tags_from_asset(
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
tags: list[str],
|
tags: list[str],
|
||||||
owner_id: str = "",
|
owner_id: str = "",
|
||||||
) -> schemas_out.TagsRemove:
|
) -> schemas_out.TagsRemove:
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
import uuid
|
||||||
|
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
Integer,
|
Integer,
|
||||||
@ -135,7 +136,7 @@ class AssetLocation(Base):
|
|||||||
class AssetInfo(Base):
|
class AssetInfo(Base):
|
||||||
__tablename__ = "assets_info"
|
__tablename__ = "assets_info"
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||||
owner_id: Mapped[str] = mapped_column(String(128), nullable=False, default="")
|
owner_id: Mapped[str] = mapped_column(String(128), nullable=False, default="")
|
||||||
name: Mapped[str] = mapped_column(String(512), nullable=False)
|
name: Mapped[str] = mapped_column(String(512), nullable=False)
|
||||||
asset_hash: Mapped[str] = mapped_column(
|
asset_hash: Mapped[str] = mapped_column(
|
||||||
@ -194,7 +195,6 @@ class AssetInfo(Base):
|
|||||||
Index("ix_assets_info_name", "name"),
|
Index("ix_assets_info_name", "name"),
|
||||||
Index("ix_assets_info_created_at", "created_at"),
|
Index("ix_assets_info_created_at", "created_at"),
|
||||||
Index("ix_assets_info_last_access_time", "last_access_time"),
|
Index("ix_assets_info_last_access_time", "last_access_time"),
|
||||||
{"sqlite_autoincrement": True},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_dict(self, include_none: bool = False) -> dict[str, Any]:
|
def to_dict(self, include_none: bool = False) -> dict[str, Any]:
|
||||||
@ -209,8 +209,8 @@ class AssetInfo(Base):
|
|||||||
class AssetInfoMeta(Base):
|
class AssetInfoMeta(Base):
|
||||||
__tablename__ = "asset_info_meta"
|
__tablename__ = "asset_info_meta"
|
||||||
|
|
||||||
asset_info_id: Mapped[int] = mapped_column(
|
asset_info_id: Mapped[str] = mapped_column(
|
||||||
Integer, ForeignKey("assets_info.id", ondelete="CASCADE"), primary_key=True
|
String(36), ForeignKey("assets_info.id", ondelete="CASCADE"), primary_key=True
|
||||||
)
|
)
|
||||||
key: Mapped[str] = mapped_column(String(256), primary_key=True)
|
key: Mapped[str] = mapped_column(String(256), primary_key=True)
|
||||||
ordinal: Mapped[int] = mapped_column(Integer, primary_key=True, default=0)
|
ordinal: Mapped[int] = mapped_column(Integer, primary_key=True, default=0)
|
||||||
@ -233,8 +233,8 @@ class AssetInfoMeta(Base):
|
|||||||
class AssetInfoTag(Base):
|
class AssetInfoTag(Base):
|
||||||
__tablename__ = "asset_info_tags"
|
__tablename__ = "asset_info_tags"
|
||||||
|
|
||||||
asset_info_id: Mapped[int] = mapped_column(
|
asset_info_id: Mapped[str] = mapped_column(
|
||||||
Integer, ForeignKey("assets_info.id", ondelete="CASCADE"), primary_key=True
|
String(36), ForeignKey("assets_info.id", ondelete="CASCADE"), primary_key=True
|
||||||
)
|
)
|
||||||
tag_name: Mapped[str] = mapped_column(
|
tag_name: Mapped[str] = mapped_column(
|
||||||
String(512), ForeignKey("tags.name", ondelete="RESTRICT"), primary_key=True
|
String(512), ForeignKey("tags.name", ondelete="RESTRICT"), primary_key=True
|
||||||
|
|||||||
@ -30,7 +30,7 @@ async def get_asset_by_hash(session: AsyncSession, *, asset_hash: str) -> Option
|
|||||||
return await session.get(Asset, asset_hash)
|
return await session.get(Asset, asset_hash)
|
||||||
|
|
||||||
|
|
||||||
async def get_asset_info_by_id(session: AsyncSession, *, asset_info_id: int) -> Optional[AssetInfo]:
|
async def get_asset_info_by_id(session: AsyncSession, *, asset_info_id: str) -> Optional[AssetInfo]:
|
||||||
return await session.get(AssetInfo, asset_info_id)
|
return await session.get(AssetInfo, asset_info_id)
|
||||||
|
|
||||||
|
|
||||||
@ -100,13 +100,13 @@ async def ingest_fs_asset(
|
|||||||
"asset_updated": bool,
|
"asset_updated": bool,
|
||||||
"state_created": bool,
|
"state_created": bool,
|
||||||
"state_updated": bool,
|
"state_updated": bool,
|
||||||
"asset_info_id": int | None,
|
"asset_info_id": str | None,
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
locator = os.path.abspath(abs_path)
|
locator = os.path.abspath(abs_path)
|
||||||
datetime_now = utcnow()
|
datetime_now = utcnow()
|
||||||
|
|
||||||
out = {
|
out: dict[str, Any] = {
|
||||||
"asset_created": False,
|
"asset_created": False,
|
||||||
"asset_updated": False,
|
"asset_updated": False,
|
||||||
"state_created": False,
|
"state_created": False,
|
||||||
@ -187,7 +187,7 @@ async def ingest_fs_asset(
|
|||||||
last_access_time=datetime_now,
|
last_access_time=datetime_now,
|
||||||
)
|
)
|
||||||
session.add(info)
|
session.add(info)
|
||||||
await session.flush() # get info.id
|
await session.flush() # get info.id (UUID)
|
||||||
out["asset_info_id"] = info.id
|
out["asset_info_id"] = info.id
|
||||||
|
|
||||||
existing_info = (
|
existing_info = (
|
||||||
@ -263,11 +263,11 @@ async def ingest_fs_asset(
|
|||||||
async def touch_asset_infos_by_fs_path(
|
async def touch_asset_infos_by_fs_path(
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
abs_path: str,
|
file_path: str,
|
||||||
ts: Optional[datetime] = None,
|
ts: Optional[datetime] = None,
|
||||||
only_if_newer: bool = True,
|
only_if_newer: bool = True,
|
||||||
) -> int:
|
) -> int:
|
||||||
locator = os.path.abspath(abs_path)
|
locator = os.path.abspath(file_path)
|
||||||
ts = ts or utcnow()
|
ts = ts or utcnow()
|
||||||
|
|
||||||
stmt = sa.update(AssetInfo).where(
|
stmt = sa.update(AssetInfo).where(
|
||||||
@ -298,7 +298,7 @@ async def touch_asset_infos_by_fs_path(
|
|||||||
async def touch_asset_info_by_id(
|
async def touch_asset_info_by_id(
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
ts: Optional[datetime] = None,
|
ts: Optional[datetime] = None,
|
||||||
only_if_newer: bool = True,
|
only_if_newer: bool = True,
|
||||||
) -> int:
|
) -> int:
|
||||||
@ -325,7 +325,7 @@ async def list_asset_infos_page(
|
|||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
sort: str = "created_at",
|
sort: str = "created_at",
|
||||||
order: str = "desc",
|
order: str = "desc",
|
||||||
) -> tuple[list[AssetInfo], dict[int, list[str]], int]:
|
) -> tuple[list[AssetInfo], dict[str, list[str]], int]:
|
||||||
"""Return page of AssetInfo rows in the viewers visibility."""
|
"""Return page of AssetInfo rows in the viewers visibility."""
|
||||||
base = (
|
base = (
|
||||||
select(AssetInfo)
|
select(AssetInfo)
|
||||||
@ -373,8 +373,8 @@ async def list_asset_infos_page(
|
|||||||
infos = (await session.execute(base)).scalars().unique().all()
|
infos = (await session.execute(base)).scalars().unique().all()
|
||||||
|
|
||||||
# Collect tags in bulk (single query)
|
# Collect tags in bulk (single query)
|
||||||
id_list = [i.id for i in infos]
|
id_list: list[str] = [i.id for i in infos]
|
||||||
tag_map: dict[int, list[str]] = defaultdict(list)
|
tag_map: dict[str, list[str]] = defaultdict(list)
|
||||||
if id_list:
|
if id_list:
|
||||||
rows = await session.execute(
|
rows = await session.execute(
|
||||||
select(AssetInfoTag.asset_info_id, Tag.name)
|
select(AssetInfoTag.asset_info_id, Tag.name)
|
||||||
@ -390,7 +390,7 @@ async def list_asset_infos_page(
|
|||||||
async def fetch_asset_info_and_asset(
|
async def fetch_asset_info_and_asset(
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
owner_id: str = "",
|
owner_id: str = "",
|
||||||
) -> Optional[tuple[AssetInfo, Asset]]:
|
) -> Optional[tuple[AssetInfo, Asset]]:
|
||||||
stmt = (
|
stmt = (
|
||||||
@ -412,7 +412,7 @@ async def fetch_asset_info_and_asset(
|
|||||||
async def fetch_asset_info_asset_and_tags(
|
async def fetch_asset_info_asset_and_tags(
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
owner_id: str = "",
|
owner_id: str = "",
|
||||||
) -> Optional[tuple[AssetInfo, Asset, list[str]]]:
|
) -> Optional[tuple[AssetInfo, Asset, list[str]]]:
|
||||||
stmt = (
|
stmt = (
|
||||||
@ -449,7 +449,7 @@ async def get_cache_state_by_asset_hash(session: AsyncSession, *, asset_hash: st
|
|||||||
|
|
||||||
async def list_asset_locations(
|
async def list_asset_locations(
|
||||||
session: AsyncSession, *, asset_hash: str, provider: Optional[str] = None
|
session: AsyncSession, *, asset_hash: str, provider: Optional[str] = None
|
||||||
) -> list[AssetLocation]:
|
) -> list[AssetLocation] | Sequence[AssetLocation]:
|
||||||
stmt = select(AssetLocation).where(AssetLocation.asset_hash == asset_hash)
|
stmt = select(AssetLocation).where(AssetLocation.asset_hash == asset_hash)
|
||||||
if provider:
|
if provider:
|
||||||
stmt = stmt.where(AssetLocation.provider == provider)
|
stmt = stmt.where(AssetLocation.provider == provider)
|
||||||
@ -545,7 +545,7 @@ async def create_asset_info_for_existing_asset(
|
|||||||
async def set_asset_info_tags(
|
async def set_asset_info_tags(
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
tags: Sequence[str],
|
tags: Sequence[str],
|
||||||
origin: str = "manual",
|
origin: str = "manual",
|
||||||
) -> dict:
|
) -> dict:
|
||||||
@ -586,7 +586,7 @@ async def set_asset_info_tags(
|
|||||||
async def update_asset_info_full(
|
async def update_asset_info_full(
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
tags: Optional[Sequence[str]] = None,
|
tags: Optional[Sequence[str]] = None,
|
||||||
user_metadata: Optional[dict] = None,
|
user_metadata: Optional[dict] = None,
|
||||||
@ -634,7 +634,7 @@ async def update_asset_info_full(
|
|||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
async def delete_asset_info_by_id(session: AsyncSession, *, asset_info_id: int, owner_id: str) -> bool:
|
async def delete_asset_info_by_id(session: AsyncSession, *, asset_info_id: str, owner_id: str) -> bool:
|
||||||
"""Delete the user-visible AssetInfo row. Cascades clear tags and metadata."""
|
"""Delete the user-visible AssetInfo row. Cascades clear tags and metadata."""
|
||||||
res = await session.execute(delete(AssetInfo).where(
|
res = await session.execute(delete(AssetInfo).where(
|
||||||
AssetInfo.id == asset_info_id,
|
AssetInfo.id == asset_info_id,
|
||||||
@ -646,7 +646,7 @@ async def delete_asset_info_by_id(session: AsyncSession, *, asset_info_id: int,
|
|||||||
async def replace_asset_info_metadata_projection(
|
async def replace_asset_info_metadata_projection(
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
user_metadata: Optional[dict],
|
user_metadata: Optional[dict],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Replaces the `assets_info.user_metadata` AND rebuild the projection rows in `asset_info_meta`."""
|
"""Replaces the `assets_info.user_metadata` AND rebuild the projection rows in `asset_info_meta`."""
|
||||||
@ -683,7 +683,7 @@ async def replace_asset_info_metadata_projection(
|
|||||||
await session.flush()
|
await session.flush()
|
||||||
|
|
||||||
|
|
||||||
async def get_asset_tags(session: AsyncSession, *, asset_info_id: int) -> list[str]:
|
async def get_asset_tags(session: AsyncSession, *, asset_info_id: str) -> list[str]:
|
||||||
return [
|
return [
|
||||||
tag_name
|
tag_name
|
||||||
for (tag_name,) in (
|
for (tag_name,) in (
|
||||||
@ -763,7 +763,7 @@ async def list_tags_with_usage(
|
|||||||
async def add_tags_to_asset_info(
|
async def add_tags_to_asset_info(
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
tags: Sequence[str],
|
tags: Sequence[str],
|
||||||
origin: str = "manual",
|
origin: str = "manual",
|
||||||
create_if_missing: bool = True,
|
create_if_missing: bool = True,
|
||||||
@ -829,7 +829,7 @@ async def add_tags_to_asset_info(
|
|||||||
async def remove_tags_from_asset_info(
|
async def remove_tags_from_asset_info(
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
asset_info_id: int,
|
asset_info_id: str,
|
||||||
tags: Sequence[str],
|
tags: Sequence[str],
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Removes tags from an AssetInfo.
|
"""Removes tags from an AssetInfo.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user