diff --git a/app/assets/api/routes.py b/app/assets/api/routes.py index 9ec13122a..c2fc2a68b 100644 --- a/app/assets/api/routes.py +++ b/app/assets/api/routes.py @@ -1,9 +1,10 @@ import logging -import uuid -import urllib.parse import os -from aiohttp import web +import urllib.parse +import uuid +from typing import Any +from aiohttp import web from pydantic import ValidationError import app.assets.manager as manager @@ -18,8 +19,6 @@ from app.assets.api.schemas_in import ( ) from app.assets.api.upload import parse_multipart_upload from app.assets.scanner import seed_assets as scanner_seed_assets -from typing import Any - ROUTES = web.RouteTableDef() USER_MANAGER: user_manager.UserManager | None = None diff --git a/app/assets/database/models.py b/app/assets/database/models.py index ea9fc198e..20ac81e27 100644 --- a/app/assets/database/models.py +++ b/app/assets/database/models.py @@ -2,8 +2,8 @@ from __future__ import annotations import uuid from datetime import datetime - from typing import Any + from sqlalchemy import ( JSON, BigInteger, @@ -21,7 +21,7 @@ from sqlalchemy import ( from sqlalchemy.orm import Mapped, foreign, mapped_column, relationship from app.assets.helpers import get_utc_now -from app.database.models import to_dict, Base +from app.database.models import Base, to_dict class Asset(Base): diff --git a/app/assets/database/queries/__init__.py b/app/assets/database/queries/__init__.py index 628a2ee53..db983d276 100644 --- a/app/assets/database/queries/__init__.py +++ b/app/assets/database/queries/__init__.py @@ -3,55 +3,52 @@ from app.assets.database.queries.asset import ( asset_exists_by_hash, + bulk_insert_assets, get_asset_by_hash, upsert_asset, - bulk_insert_assets, ) - from app.assets.database.queries.asset_info import ( asset_info_exists_for_asset_id, - get_asset_info_by_id, - insert_asset_info, - get_or_create_asset_info, - update_asset_info_timestamps, - list_asset_infos_page, - fetch_asset_info_asset_and_tags, + bulk_insert_asset_infos_ignore_conflicts, + delete_asset_info_by_id, fetch_asset_info_and_asset, + fetch_asset_info_asset_and_tags, + get_asset_info_by_id, + get_asset_info_ids_by_ids, + get_or_create_asset_info, + insert_asset_info, + list_asset_infos_page, + set_asset_info_metadata, + set_asset_info_preview, update_asset_info_access_time, update_asset_info_name, + update_asset_info_timestamps, update_asset_info_updated_at, - set_asset_info_metadata, - delete_asset_info_by_id, - set_asset_info_preview, - bulk_insert_asset_infos_ignore_conflicts, - get_asset_info_ids_by_ids, ) - from app.assets.database.queries.cache_state import ( CacheStateRow, + bulk_insert_cache_states_ignore_conflicts, + bulk_set_needs_verify, + delete_assets_by_ids, + delete_cache_states_by_ids, + delete_cache_states_outside_prefixes, + delete_orphaned_seed_asset, + get_cache_states_by_paths_and_asset_ids, + get_cache_states_for_prefixes, + get_orphaned_seed_asset_ids, list_cache_states_by_asset_id, upsert_cache_state, - delete_cache_states_outside_prefixes, - get_orphaned_seed_asset_ids, - delete_assets_by_ids, - get_cache_states_for_prefixes, - bulk_set_needs_verify, - delete_cache_states_by_ids, - delete_orphaned_seed_asset, - bulk_insert_cache_states_ignore_conflicts, - get_cache_states_by_paths_and_asset_ids, ) - from app.assets.database.queries.tags import ( + add_missing_tag_for_asset_id, + add_tags_to_asset_info, + bulk_insert_tags_and_meta, ensure_tags_exist, get_asset_tags, - set_asset_info_tags, - add_tags_to_asset_info, - remove_tags_from_asset_info, - add_missing_tag_for_asset_id, - remove_missing_tag_for_asset_id, list_tags_with_usage, - bulk_insert_tags_and_meta, + remove_missing_tag_for_asset_id, + remove_tags_from_asset_info, + set_asset_info_tags, ) __all__ = [ diff --git a/app/assets/database/queries/asset_info.py b/app/assets/database/queries/asset_info.py index 3769cc185..38724b6d1 100644 --- a/app/assets/database/queries/asset_info.py +++ b/app/assets/database/queries/asset_info.py @@ -10,15 +10,19 @@ from decimal import Decimal from typing import Sequence import sqlalchemy as sa -from sqlalchemy import select, delete, exists +from sqlalchemy import delete, exists, select from sqlalchemy.dialects import sqlite from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import Session, contains_eager, noload from app.assets.database.models import ( - Asset, AssetInfo, AssetInfoMeta, AssetInfoTag, Tag + Asset, + AssetInfo, + AssetInfoMeta, + AssetInfoTag, + Tag, ) -from app.assets.helpers import escape_sql_like_string, normalize_tags, get_utc_now +from app.assets.helpers import escape_sql_like_string, get_utc_now, normalize_tags def check_is_scalar(v): diff --git a/app/assets/database/queries/tags.py b/app/assets/database/queries/tags.py index 443f30ee8..497e74870 100644 --- a/app/assets/database/queries/tags.py +++ b/app/assets/database/queries/tags.py @@ -1,13 +1,13 @@ from typing import Iterable, Sequence import sqlalchemy as sa -from sqlalchemy import select, delete, func +from sqlalchemy import delete, func, select from sqlalchemy.dialects import sqlite from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import Session from app.assets.database.models import AssetInfo, AssetInfoMeta, AssetInfoTag, Tag -from app.assets.helpers import escape_sql_like_string, normalize_tags, get_utc_now +from app.assets.helpers import escape_sql_like_string, get_utc_now, normalize_tags MAX_BIND_PARAMS = 800 diff --git a/app/assets/manager.py b/app/assets/manager.py index 63f537832..797e82274 100644 --- a/app/assets/manager.py +++ b/app/assets/manager.py @@ -7,17 +7,16 @@ It should NOT contain business logic or direct SQLAlchemy usage. Architecture: API Routes -> manager.py (schema transformation) -> services/ (business logic) -> queries/ (DB ops) """ -import os -import mimetypes import contextlib +import mimetypes +import os from typing import Sequence from pydantic import ValidationError -import folder_paths import app.assets.services.hashing as hashing -from app.database.db import create_session -from app.assets.api import schemas_out, schemas_in +import folder_paths +from app.assets.api import schemas_in, schemas_out from app.assets.api.schemas_in import ( AssetNotFoundError, AssetValidationError, @@ -36,21 +35,26 @@ from app.assets.database.queries import ( update_asset_info_access_time, ) from app.assets.helpers import select_best_live_path -from app.assets.services.path_utils import ( - validate_path_within_base, - resolve_destination_from_tags, -) from app.assets.services import ( apply_tags, - delete_asset_reference as svc_delete_asset_reference, get_asset_detail, ingest_file_from_path, register_existing_asset, remove_tags, - set_asset_preview as svc_set_asset_preview, update_asset_metadata, ) +from app.assets.services import ( + delete_asset_reference as svc_delete_asset_reference, +) +from app.assets.services import ( + set_asset_preview as svc_set_asset_preview, +) +from app.assets.services.path_utils import ( + resolve_destination_from_tags, + validate_path_within_base, +) from app.assets.services.tagging import list_tags as svc_list_tags +from app.database.db import create_session def _validate_sort_field(requested: str | None) -> str: diff --git a/app/assets/scanner.py b/app/assets/scanner.py index 91f37c456..86e30e8da 100644 --- a/app/assets/scanner.py +++ b/app/assets/scanner.py @@ -5,26 +5,26 @@ import time import uuid from typing import Literal -import folder_paths from sqlalchemy.orm import Session +import folder_paths from app.assets.database.queries import ( add_missing_tag_for_asset_id, - ensure_tags_exist, - remove_missing_tag_for_asset_id, - delete_cache_states_outside_prefixes, - get_orphaned_seed_asset_ids, - delete_assets_by_ids, - get_cache_states_for_prefixes, - bulk_set_needs_verify, - delete_cache_states_by_ids, - delete_orphaned_seed_asset, + bulk_insert_asset_infos_ignore_conflicts, bulk_insert_assets, bulk_insert_cache_states_ignore_conflicts, - get_cache_states_by_paths_and_asset_ids, - bulk_insert_asset_infos_ignore_conflicts, - get_asset_info_ids_by_ids, bulk_insert_tags_and_meta, + bulk_set_needs_verify, + delete_assets_by_ids, + delete_cache_states_by_ids, + delete_cache_states_outside_prefixes, + delete_orphaned_seed_asset, + ensure_tags_exist, + get_asset_info_ids_by_ids, + get_cache_states_by_paths_and_asset_ids, + get_cache_states_for_prefixes, + get_orphaned_seed_asset_ids, + remove_missing_tag_for_asset_id, ) from app.assets.helpers import get_utc_now from app.assets.services.path_utils import ( @@ -34,7 +34,6 @@ from app.assets.services.path_utils import ( ) from app.database.db import create_session, dependencies_available - RootType = Literal["models", "input", "output"] diff --git a/app/assets/services/__init__.py b/app/assets/services/__init__.py index c5535bac3..7d4e94a80 100644 --- a/app/assets/services/__init__.py +++ b/app/assets/services/__init__.py @@ -2,20 +2,20 @@ # Business logic that orchestrates database queries and filesystem operations # Services own session lifecycle via create_session() +from app.assets.services.asset_management import ( + delete_asset_reference, + get_asset_detail, + set_asset_preview, + update_asset_metadata, +) from app.assets.services.ingest import ( ingest_file_from_path, register_existing_asset, ) -from app.assets.services.asset_management import ( - get_asset_detail, - update_asset_metadata, - delete_asset_reference, - set_asset_preview, -) from app.assets.services.tagging import ( apply_tags, - remove_tags, list_tags, + remove_tags, ) __all__ = [ diff --git a/app/assets/services/asset_management.py b/app/assets/services/asset_management.py index 1da6bc6bf..e18fea73e 100644 --- a/app/assets/services/asset_management.py +++ b/app/assets/services/asset_management.py @@ -12,14 +12,6 @@ import os from typing import Sequence from app.assets.database.models import Asset -from app.database.db import create_session -from app.assets.helpers import select_best_live_path -from app.assets.services.path_utils import compute_relative_filename -from app.assets.services.schemas import ( - AssetDetailResult, - extract_asset_data, - extract_info_data, -) from app.assets.database.queries import ( asset_info_exists_for_asset_id, delete_asset_info_by_id, @@ -32,6 +24,14 @@ from app.assets.database.queries import ( update_asset_info_name, update_asset_info_updated_at, ) +from app.assets.helpers import select_best_live_path +from app.assets.services.path_utils import compute_relative_filename +from app.assets.services.schemas import ( + AssetDetailResult, + extract_asset_data, + extract_info_data, +) +from app.database.db import create_session def get_asset_detail( diff --git a/app/assets/services/hashing.py b/app/assets/services/hashing.py index 8efd3adf9..b07a163ce 100644 --- a/app/assets/services/hashing.py +++ b/app/assets/services/hashing.py @@ -1,6 +1,6 @@ -from typing import IO -import os import asyncio +import os +from typing import IO try: from blake3 import blake3 diff --git a/app/assets/services/ingest.py b/app/assets/services/ingest.py index d4844d247..bc03d9906 100644 --- a/app/assets/services/ingest.py +++ b/app/assets/services/ingest.py @@ -12,16 +12,10 @@ from typing import Sequence from sqlalchemy import select from app.assets.database.models import Asset, Tag -from app.database.db import create_session -from app.assets.helpers import normalize_tags, select_best_live_path -from app.assets.services.path_utils import compute_relative_filename -from app.assets.services.schemas import ( - RegisterAssetResult, - extract_asset_data, - extract_info_data, -) from app.assets.database.queries import ( + add_tags_to_asset_info, get_asset_by_hash, + get_asset_tags, get_or_create_asset_info, list_cache_states_by_asset_id, remove_missing_tag_for_asset_id, @@ -30,9 +24,15 @@ from app.assets.database.queries import ( update_asset_info_timestamps, upsert_asset, upsert_cache_state, - add_tags_to_asset_info, - get_asset_tags, ) +from app.assets.helpers import normalize_tags, select_best_live_path +from app.assets.services.path_utils import compute_relative_filename +from app.assets.services.schemas import ( + RegisterAssetResult, + extract_asset_data, + extract_info_data, +) +from app.database.db import create_session def ingest_file_from_path( diff --git a/app/assets/services/path_utils.py b/app/assets/services/path_utils.py index 0d76953fd..cd2f87d6c 100644 --- a/app/assets/services/path_utils.py +++ b/app/assets/services/path_utils.py @@ -3,7 +3,6 @@ from pathlib import Path from typing import Literal import folder_paths - from app.assets.helpers import normalize_tags diff --git a/app/assets/services/tagging.py b/app/assets/services/tagging.py index 8cdce11cf..f6247dfa8 100644 --- a/app/assets/services/tagging.py +++ b/app/assets/services/tagging.py @@ -6,13 +6,13 @@ Business logic for: - remove_tags: Remove tags from an asset - list_tags: List tags with usage counts """ -from app.database.db import create_session from app.assets.database.queries import ( add_tags_to_asset_info, get_asset_info_by_id, list_tags_with_usage, remove_tags_from_asset_info, ) +from app.database.db import create_session def apply_tags(