first commit

This commit is contained in:
2026-04-01 13:48:40 -07:00
commit 61d386a7c7
178 changed files with 3827 additions and 0 deletions

289
app/pipelines/crud.py Normal file
View File

@@ -0,0 +1,289 @@
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 enititys"""
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}
print(f"FORMAT: output creado con {len(ctx['output'])} campos")
else:
print("FORMAT: No hay entity para formatear")
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("execurte", self._execute)
self.add_step("format_output", self._format)
async def _validate_id(self, ctx):
input_data = ctx["input"].raw_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):
data = ctx["input"].get_validated()
ctx["validated_data"] = data.dict() if data else {}
return ctx
async def _validate_id(self, ctx):
entity_id = ctx["validated_data"].get("id")
if not entity_id:
raise ValueError("Se rqeuiere 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"] = {
"id": ctx["entity"].id,
"message": f"{self.model.__name__} actualizado exitosamente"
}
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", self._validate)
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["input"].raw_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"]["message"] = f"{self.model.__name__} eliminado corectamente"
ctx["output"]["deleted_at"] = ctx["entity"].deleted_at.isoformat()
ctx["output"]["deleted_by"] = ctx["entity"].delted_by
return ctx
class ListPipe(Pipeline):
"""Pipeline prefab to list entitys"""
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