from typing import Type, Dict, Any, List from sqlalchemy.orm import Session from app.pipelines.base import Pipeline # # from app.serviceInput.base import ServiceInput from app.core.auth import CurrentUser class CreatePipe(Pipeline): """Pipe prefab to create entities""" def __init__(self, db: Session, user: CurrentUser, model: Type, repository): super().__init__(db, user, f"CREATE_{model.__tablename__.upper()}") self.model = model self.repository = repository self._build() def _build(self): """Build steps to Pipe""" self.add_step("Validate", self._validate) self.add_step("check_permissions", self._check_permissions) self.add_step("execute", self._execute) self.add_step("format_output", self._format) async def _validate(self, ctx): data = ctx.get("input_data", {}) if ctx.get("schema"): validated = ctx["schema"](**data) ctx["validated_data"] = validated.dict() else: ctx["validated_data"] = data return ctx async def _check_permissions(self, ctx): if ctx.get("permission"): if not ctx.get("user"): ctx["error"] = "Usuario no autenticado" return ctx async def _execute(self, ctx): if ctx.get("error"): return ctx try: created_by = ctx["user"].id if ctx.get("user") else None entity = self.repository.create(ctx["validated_data"], created_by) ctx["entity"] = entity except Exception as e: ctx["error"] = str(e) return ctx async def _format(self, ctx): if ctx.get("error"): ctx["output"] = None return ctx if ctx.get("entity"): ctx["output"] = {c.name: getattr(ctx["entity"], c.name) for c in self.model.__table__.columns} else: ctx["output"] = None return ctx class ReadPipe(Pipeline): """ Read prefab """ def __init__(self, db: Session, user: CurrentUser, model: Type, repository): super().__init__(db, user, f"READ_{model.__tablename__.upper()}") self.model = model self.repository = repository self._build() def _build(self): self.add_step("validate_id", self._validate_id) self.add_step("check_permissions", self._check_permissions) self.add_step("execute", self._execute) self.add_step("format_output", self._format) async def _validate_id(self, ctx): input_data = ctx.get("input_data", {}) entity_id = input_data.get("id") if not entity_id: raise ValueError("se requiere ID") ctx["entity_id"] = entity_id return ctx async def _check_permissions(self, ctx): return ctx async def _execute(self, ctx): entity = self.repository.get_by_id(ctx["entity_id"]) if not entity: raise ValueError(f"{self.model.__name__} no encontrado") ctx["entity"] = entity ctx["output"] = entity return ctx async def _format(self, ctx): ctx["output"] = {c.name: getattr(ctx["entity"], c.name) for c in self.model.__table__.columns} return ctx class UpdatePipe(Pipeline): """Pipe prefab to Update""" def __init__(self, db:Session, user:CurrentUser, model: Type, repository): super().__init__(db, user, f"UPDATE_{model.__tablename__.upper()}") self.model = model self.repository = repository self._build() def _build(self): self.add_step("validate", self._validate) self.add_step("validate_id", self._validate_id) self.add_step("check_permissions", self._check_permissions) self.add_step("execute", self._execute) self.add_step("certify", self._certify) self.add_step("format_output", self._format) async def _validate(self, ctx): input_data = ctx.get("input_data", {}) if ctx.get("schema"): validated = ctx["schema"](**input_data) ctx["validated_data"] = validated.dict() else: ctx["validated_data"] = input_data return ctx async def _validate_id(self, ctx): entity_id = ctx["validated_data"].get("id") if not entity_id: raise ValueError("Se requiere ID") ctx["entity_id"] = entity_id return ctx async def _check_permissions(self, ctx): return ctx async def _execute(self, ctx): entity = self.repository.update(ctx["entity_id"], ctx["validated_data"]) if not entity: raise ValueError(f"{self.model.__name__} no encontrado") ctx["entity"] = entity ctx["output"] = entity return ctx async def _certify(self, ctx): return ctx async def _format(self, ctx): ctx["output"] = {c.name: getattr(ctx["entity"], c.name) for c in self.model.__table__.columns} return ctx class SoftDelete(Pipeline): """Pipe prefab to SoftDelete""" def __init__(self, db:Session, user:CurrentUser, model: Type, repository): super().__init__(db, user, f"DELETE_{model.__tablename__.upper()}") self.model = model self.repository = repository self._build() def _build(self): self.add_step("validate_id", self._validate_id) self.add_step("check_permissions", self._check_permissions) self.add_step("check_already_deleted", self._check_already_deleted) self.add_step("execute", self._execute) self.add_step("certify", self._certify) self.add_step("format_output", self._format) async def _validate_id(self, ctx): input_data = ctx.get("input_data", {}) entity_id = input_data.get("id") if not entity_id: raise ValueError("se requiere ID") ctx["entity_id"] = entity_id return ctx async def _check_permissions(self, ctx): return ctx async def _check_already_deleted(self, ctx): """Verify entity has no deleted""" entity = self.repository.get_by_id(ctx["entity_id"]) if not entity: raise ValueError(f"{self.model.__name__} no encontrado") if not entity.is_active or entity.deleted_at is not None: raise ValueError(f"{self.model.__name__} ya esta eliminado") ctx["entity"] = entity return ctx async def _execute(self, ctx): """ SoftDelete implemented""" entity = ctx["entity"] from datetime import datetime entity.is_active = False entity.deleted_at = datetime.utcnow() entity.deleted_by = ctx["user"].id self.db.commit() self.db.refresh(entity) ctx["deleted"] = True ctx["output"] = {"id": entity.id, "deleted": True} return ctx async def _certify(self, ctx): return ctx async def _format(self, ctx): ctx["output"] = { "id": ctx["entity"].id, "message": f"{self.model.__name__} eliminado correctamente", "deleted_at": ctx["entity"].deleted_at.isoformat() if ctx["entity"].deleted_at else None, "deleted_by": ctx["entity"].deleted_by } return ctx class ListPipe(Pipeline): """Pipeline prefab to list entities""" def __init__(self, db: Session, user: CurrentUser, model: Type, repository): super().__init__(db, user, f"LIST_{model.__tablename__.upper()}") self.model = model self.repository = repository self._skip = 0 self._limit = 100 self._filters = {} self._include_inactive = False self._build() def with_pagination(self, skip: int, limit: int) -> 'ListPipe': self._skip = skip self._limit = limit return self def with_filters(self, filters: Dict) -> 'ListPipe': self._filters = filters return self def include_inactive(self, value: bool = True) -> 'ListPipe': self._include_inactive = value return self def _build(self): self.add_step("parse_params", self._parse_params) self.add_step("check_permissions", self._check_permissions) self.add_step("execute", self._execute) self.add_step("format_output", self._format) async def _parse_params(self, ctx): ctx["skip"] = self._skip ctx["limit"] = self._limit ctx["filters"] = self._filters ctx["include_inactive"] = self._include_inactive return ctx async def _check_permissions(self, ctx): return ctx async def _execute(self, ctx): entities = self.repository.get_all( skip=ctx["skip"], limit=ctx["limit"], filters=ctx["filters"] ) ctx["entities"] = entities ctx["output"] = entities return ctx async def _format(self, ctx): ctx["output"] = [ {c.name: getattr(e, c.name) for c in self.model.__table__.columns} for e in ctx["entities"] ] return ctx