Repository: litestar-org/litestar

Issue:
StaticFilesConfig and virtual directories
I'm trying to write a ``FileSystemProtocol`` to load files from the package data using [importlib_resources](https://importlib-resources.readthedocs.io/en/latest/using.html#). But because ``directories`` is defined as ``DirectoryPath``, pydantic checks if the given directories exist in the local filesystem. 

This is not generally true, especially in any kind of virtual filesystem (e.g. a zipped package). I think this condition should be relaxed to support virtual filesystems.

https://github.com/starlite-api/starlite/blob/9bb6dcd57c10a591377cf8e3a537e9292566d5b9/starlite/config/static_files.py#L32


Discussion:
I agree. Do you want to submit a PR?

Resolving patch:
diff --git a/litestar/contrib/sqlalchemy/repository/_async.py b/litestar/contrib/sqlalchemy/repository/_async.py
--- a/litestar/contrib/sqlalchemy/repository/_async.py
+++ b/litestar/contrib/sqlalchemy/repository/_async.py
@@ -1,6 +1,6 @@
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Any, Generic, Iterable, Literal, cast
+from typing import TYPE_CHECKING, Any, Final, Generic, Iterable, Literal, cast
 
 from sqlalchemy import Result, Select, TextClause, delete, over, select, text, update
 from sqlalchemy import func as sql_func
@@ -28,6 +28,8 @@
     from sqlalchemy.engine.interfaces import _CoreSingleExecuteParams
     from sqlalchemy.ext.asyncio import AsyncSession
 
+DEFAULT_INSERTMANYVALUES_MAX_PARAMETERS: Final = 950
+
 
 class SQLAlchemyAsyncRepository(AbstractAsyncRepository[ModelT], Generic[ModelT]):
     """SQLAlchemy based implementation of the repository interface."""
@@ -157,6 +159,7 @@ async def delete_many(
         auto_commit: bool | None = None,
         auto_expunge: bool | None = None,
         id_attribute: Any | None = None,
+        chunk_size: int | None = None,
     ) -> list[ModelT]:
         """Delete instance identified by `item_id`.
 
@@ -168,6 +171,8 @@ async def delete_many(
                 :class:`SQLAlchemyAsyncRepository.auto_commit <SQLAlchemyAsyncRepository>`
             id_attribute: Allows customization of the unique identifier to use for model fetching.
                 Defaults to `id`, but can reference any surrogate or candidate key for the table.
+            chunk_size: Allows customization of the ``insertmanyvalues_max_parameters`` setting for the driver.
+                Defaults to `950` if left unset.
 
         Returns:
             The deleted instances.
@@ -177,7 +182,7 @@ async def delete_many(
         with wrap_sqlalchemy_exception():
             id_attribute = id_attribute if id_attribute is not None else self.id_attribute
             instances: list[ModelT] = []
-            chunk_size = 450
+            chunk_size = self._get_insertmanyvalues_max_parameters(chunk_size)
             for idx in range(0, len(item_ids), chunk_size):
                 chunk = item_ids[idx : min(idx + chunk_size, len(item_ids))]
                 if self._dialect.delete_executemany_returning:
@@ -202,6 +207,9 @@ async def delete_many(
                 self._expunge(instance, auto_expunge=auto_expunge)
             return instances
 
+    def _get_insertmanyvalues_max_parameters(self, chunk_size: int | None = None) -> int:
+        return chunk_size if chunk_size is not None else DEFAULT_INSERTMANYVALUES_MAX_PARAMETERS
+
     async def exists(self, **kwargs: Any) -> bool:
         """Return true if the object specified by ``kwargs`` exists.
 
diff --git a/litestar/contrib/sqlalchemy/repository/_sync.py b/litestar/contrib/sqlalchemy/repository/_sync.py
--- a/litestar/contrib/sqlalchemy/repository/_sync.py
+++ b/litestar/contrib/sqlalchemy/repository/_sync.py
@@ -2,7 +2,7 @@
 # litestar/contrib/sqlalchemy/repository/_async.py
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Any, Generic, Iterable, Literal, cast
+from typing import TYPE_CHECKING, Any, Final, Generic, Iterable, Literal, cast
 
 from sqlalchemy import Result, Select, TextClause, delete, over, select, text, update
 from sqlalchemy import func as sql_func
@@ -30,6 +30,8 @@
     from sqlalchemy.engine.interfaces import _CoreSingleExecuteParams
     from sqlalchemy.orm import Session
 
+DEFAULT_INSERTMANYVALUES_MAX_PARAMETERS: Final = 950
+
 
 class SQLAlchemySyncRepository(AbstractSyncRepository[ModelT], Generic[ModelT]):
     """SQLAlchemy based implementation of the repository interface."""
@@ -159,6 +161,7 @@ def delete_many(
         auto_commit: bool | None = None,
         auto_expunge: bool | None = None,
         id_attribute: Any | None = None,
+        chunk_size: int | None = None,
     ) -> list[ModelT]:
         """Delete instance identified by `item_id`.
 
@@ -170,6 +173,8 @@ def delete_many(
                 :class:`SQLAlchemyAsyncRepository.auto_commit <SQLAlchemyAsyncRepository>`
             id_attribute: Allows customization of the unique identifier to use for model fetching.
                 Defaults to `id`, but can reference any surrogate or candidate key for the table.
+            chunk_size: Allows customization of the ``insertmanyvalues_max_parameters`` setting for the driver.
+                Defaults to `950` if left unset.
 
         Returns:
             The deleted instances.
@@ -179,7 +184,7 @@ def delete_many(
         with wrap_sqlalchemy_exception():
             id_attribute = id_attribute if id_attribute is not None else self.id_attribute
             instances: list[ModelT] = []
-            chunk_size = 450
+            chunk_size = self._get_insertmanyvalues_max_parameters(chunk_size)
             for idx in range(0, len(item_ids), chunk_size):
                 chunk = item_ids[idx : min(idx + chunk_size, len(item_ids))]
                 if self._dialect.delete_executemany_returning:
@@ -204,6 +209,9 @@ def delete_many(
                 self._expunge(instance, auto_expunge=auto_expunge)
             return instances
 
+    def _get_insertmanyvalues_max_parameters(self, chunk_size: int | None = None) -> int:
+        return chunk_size if chunk_size is not None else DEFAULT_INSERTMANYVALUES_MAX_PARAMETERS
+
     def exists(self, **kwargs: Any) -> bool:
         """Return true if the object specified by ``kwargs`` exists.
 


Test patch:
diff --git a/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_bigint.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_bigint.py
--- a/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_bigint.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_bigint.py
@@ -305,7 +305,7 @@ async def test_repo_delete_many_method(author_repo: AuthorAsyncRepository) -> No
         BigIntAuthor(
             name="author name %d" % chunk,
         )
-        for chunk in range(1000)
+        for chunk in range(2000)
     ]
     _ = await maybe_async(author_repo.add_many(data_to_insert))
     all_objs = await maybe_async(author_repo.list())
diff --git a/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_uuid.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_uuid.py
--- a/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_uuid.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_uuid.py
@@ -411,7 +411,7 @@ async def test_repo_delete_many_method(author_repo: AuthorAsyncRepository) -> No
         UUIDAuthor(
             name="author name %d" % chunk,
         )
-        for chunk in range(1000)
+        for chunk in range(2000)
     ]
     _ = await maybe_async(author_repo.add_many(data_to_insert))
     all_objs = await maybe_async(author_repo.list())
diff --git a/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_async.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_async.py
--- a/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_async.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_async.py
@@ -203,7 +203,7 @@ async def test_sqlalchemy_repo_delete(mock_repo: SQLAlchemyAsyncRepository, monk
     mock_repo.session.commit.assert_not_called()
 
 
-async def test_sqlalchemy_repo_delete_many(mock_repo: SQLAlchemyAsyncRepository, monkeypatch: MonkeyPatch) -> None:
+async def test_sqlalchemy_repo_delete_many_uuid(mock_repo: SQLAlchemyAsyncRepository, monkeypatch: MonkeyPatch) -> None:
     """Test expected method calls for delete operation."""
 
     class UUIDModel(base.UUIDAuditBase):
@@ -212,6 +212,25 @@ class UUIDModel(base.UUIDAuditBase):
 
         ...
 
+    mock_instances = [MagicMock(), MagicMock(id=uuid4())]
+    monkeypatch.setattr(mock_repo.session, "scalars", AsyncMock(return_value=mock_instances))
+    monkeypatch.setattr(mock_repo, "model_type", UUIDModel)
+    monkeypatch.setattr(mock_repo.session, "execute", AsyncMock(return_value=mock_instances))
+    monkeypatch.setattr(mock_repo, "list", AsyncMock(return_value=mock_instances))
+    monkeypatch.setattr(mock_repo.session.bind.dialect, "insertmanyvalues_max_parameters", 2)
+
+    added_instances = await mock_repo.add_many(mock_instances)
+    instances = await mock_repo.delete_many([obj.id for obj in added_instances])
+    assert len(instances) == len(mock_instances)
+    mock_repo.session.flush.assert_called()
+    mock_repo.session.commit.assert_not_called()
+
+
+async def test_sqlalchemy_repo_delete_many_bigint(
+    mock_repo: SQLAlchemyAsyncRepository, monkeypatch: MonkeyPatch
+) -> None:
+    """Test expected method calls for delete operation."""
+
     class BigIntModel(base.BigIntAuditBase):
         """Inheriting from BigIntAuditBase gives the model 'created_at' and 'updated_at'
         columns."""
@@ -220,11 +239,11 @@ class BigIntModel(base.BigIntAuditBase):
 
     mock_instances = [MagicMock(), MagicMock(id=uuid4())]
     monkeypatch.setattr(mock_repo.session, "scalars", AsyncMock(return_value=mock_instances))
-    monkeypatch.setattr(mock_repo, "model_type", UUIDModel)
-    monkeypatch.setattr(mock_repo.session, "execute", AsyncMock(return_value=mock_instances))
     monkeypatch.setattr(mock_repo, "model_type", BigIntModel)
     monkeypatch.setattr(mock_repo.session, "execute", AsyncMock(return_value=mock_instances))
     monkeypatch.setattr(mock_repo, "list", AsyncMock(return_value=mock_instances))
+    monkeypatch.setattr(mock_repo.session.bind.dialect, "insertmanyvalues_max_parameters", 2)
+
     added_instances = await mock_repo.add_many(mock_instances)
     instances = await mock_repo.delete_many([obj.id for obj in added_instances])
     assert len(instances) == len(mock_instances)
diff --git a/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_sync.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_sync.py
--- a/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_sync.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_sync.py
@@ -202,7 +202,7 @@ def test_sqlalchemy_repo_delete(mock_repo: SQLAlchemySyncRepository, monkeypatch
     mock_repo.session.commit.assert_not_called()
 
 
-def test_sqlalchemy_repo_delete_many(mock_repo: SQLAlchemySyncRepository, monkeypatch: MonkeyPatch) -> None:
+def test_sqlalchemy_repo_delete_many_uuid(mock_repo: SQLAlchemySyncRepository, monkeypatch: MonkeyPatch) -> None:
     """Test expected method calls for delete operation."""
 
     class UUIDModel(base.UUIDAuditBase):
@@ -211,6 +211,23 @@ class UUIDModel(base.UUIDAuditBase):
 
         ...
 
+    mock_instances = [MagicMock(), MagicMock(id=uuid4())]
+    monkeypatch.setattr(mock_repo.session, "scalars", MagicMock(return_value=mock_instances))
+    monkeypatch.setattr(mock_repo, "model_type", UUIDModel)
+    monkeypatch.setattr(mock_repo.session, "execute", MagicMock(return_value=mock_instances))
+    monkeypatch.setattr(mock_repo, "list", MagicMock(return_value=mock_instances))
+    monkeypatch.setattr(mock_repo.session.bind.dialect, "insertmanyvalues_max_parameters", 100)  # type: ignore[union-attr]
+
+    added_instances = mock_repo.add_many(mock_instances)
+    instances = mock_repo.delete_many([obj.id for obj in added_instances])
+    assert len(instances) == len(mock_instances)
+    mock_repo.session.flush.assert_called()
+    mock_repo.session.commit.assert_not_called()
+
+
+def test_sqlalchemy_repo_delete_many_bigint(mock_repo: SQLAlchemySyncRepository, monkeypatch: MonkeyPatch) -> None:
+    """Test expected method calls for delete operation."""
+
     class BigIntModel(base.BigIntAuditBase):
         """Inheriting from BigIntAuditBase gives the model 'created_at' and 'updated_at'
         columns."""
@@ -219,11 +236,11 @@ class BigIntModel(base.BigIntAuditBase):
 
     mock_instances = [MagicMock(), MagicMock(id=uuid4())]
     monkeypatch.setattr(mock_repo.session, "scalars", MagicMock(return_value=mock_instances))
-    monkeypatch.setattr(mock_repo, "model_type", UUIDModel)
-    monkeypatch.setattr(mock_repo.session, "execute", MagicMock(return_value=mock_instances))
     monkeypatch.setattr(mock_repo, "model_type", BigIntModel)
     monkeypatch.setattr(mock_repo.session, "execute", MagicMock(return_value=mock_instances))
     monkeypatch.setattr(mock_repo, "list", MagicMock(return_value=mock_instances))
+    monkeypatch.setattr(mock_repo.session.bind.dialect, "insertmanyvalues_max_parameters", 100)  # type: ignore[union-attr]
+
     added_instances = mock_repo.add_many(mock_instances)
     instances = mock_repo.delete_many([obj.id for obj in added_instances])
     assert len(instances) == len(mock_instances)