"""BulkOps: bulk create / update / delete.""" from __future__ import annotations import pytest from sqlalchemy.orm import Session from tests.framework._fixtures import Thing, ThingCreate, ThingUpdate from ypms.framework.bulk import BulkOps, BulkUpdateItem from ypms.framework.crud import CRUDService from ypms.users.models import User @pytest.fixture def bulk(db: Session) -> BulkOps: Thing.__table__.create(bind=db.get_bind(), checkfirst=True) crud = CRUDService[Thing, ThingCreate, ThingUpdate](Thing, entity="Thing") return BulkOps[Thing, ThingCreate, ThingUpdate](crud) @pytest.fixture def actor(db: Session) -> User: u = User(username="op", email="op@example.com", password_hash="x") db.add(u) db.flush() return u def test_bulk_create_reports_each_result(bulk: BulkOps, db: Session, actor: User) -> None: payloads = [ThingCreate(name="a"), ThingCreate(name="b"), ThingCreate(name="c")] result = bulk.create(db, payloads, actor=actor) assert len(result.succeeded) == 3 assert result.failed == [] def test_bulk_update_applies_patches(bulk: BulkOps, db: Session, actor: User) -> None: created = bulk.create( db, [ThingCreate(name="a"), ThingCreate(name="b")], actor=actor ) id_a, id_b = created.succeeded items = [ BulkUpdateItem(id=id_a, patch={"color": "red"}), BulkUpdateItem(id=id_b, patch={"color": "blue"}), ] result = bulk.update(db, items, ThingUpdate, actor=actor) assert sorted(result.succeeded) == sorted([id_a, id_b]) a = db.get(Thing, id_a) b = db.get(Thing, id_b) assert a is not None and b is not None assert a.color == "red" assert b.color == "blue" def test_bulk_delete_soft_deletes_all(bulk: BulkOps, db: Session, actor: User) -> None: created = bulk.create( db, [ThingCreate(name=f"n{i}") for i in range(3)], actor=actor ) result = bulk.delete(db, created.succeeded, actor=actor) assert len(result.succeeded) == 3 for id_ in created.succeeded: t = db.get(Thing, id_) assert t is not None and t.is_deleted def test_bulk_reports_failures_without_aborting(bulk: BulkOps, db: Session, actor: User) -> None: result = bulk.delete(db, [1, 2, 3], actor=actor) # nothing exists assert result.succeeded == [] assert len(result.failed) == 3 assert all("error" in f for f in result.failed)