data - PowerSystem2024/CapybaraFilms_ProyectoTercerSemestre GitHub Wiki

arquitc

🎯 Introducción

Este documento detalla la infraestructura de conectividad a la base de datos proporcionada por la clase DatabaseConnection. Esta clase actúa como el componente central para la integración con PostgreSQL en el sistema Capybara Films, manejando la gestión de conexiones, el procesamiento de transacciones, la ejecución de consultas y la recuperación de errores para todas las operaciones de base de datos a lo largo de la aplicación.

📖 Contenido:


📄 DatabaseConnection.py

1. Configuración de la Conexión

La clase DatabaseConnection está configurada para conectarse a una base de datos PostgreSQL alojada en Railway. Los parámetros de conexión están codificados en el constructor e incluyen el nombre de la base de datos, las credenciales de usuario, el host y la información del puerto.

Parámetro Valor Predeterminado Propósito
database railway Nombre de la base de datos objetivo
user postgres Cuenta de usuario de la base de datos
password [hardcoded] Credencial de autenticación
host turntable.proxy.rlwy.net Nombre de host del proxy de Railway
port 44390 Puerto del proxy de Railway

La configuración de la conexión se almacena en una estructura de diccionario en CapybaraFilms/data/DatabaseConnection y se utiliza a lo largo del ciclo de vida de la conexión.

🔸 Desempaquetado de Config

El método _conectar() utiliza el operador de desempaquetado ** para pasar los parámetros de configuración a psycopg2.connect().

¿Por qué se usa **self.config?

  • Flexibilidad: Permite pasar todos los parámetros del diccionario como argumentos nombrados
  • Mantenibilidad: Si se agregan nuevos parámetros al diccionario, no es necesario modificar la llamada a connect()
  • Legibilidad: Evita tener que especificar cada parámetro individualmente en la llamada

Esto es equivalente a escribir:

psycopg2.connect(  
    database=self.config["database"],  
    user=self.config["user"],   
    password=self.config["password"],  
    host=self.config["host"],  
    port=self.config["port"]  
)

2. Arquitectura de la Clase DatabaseConnection

La clase DatabaseConnection encapsula la lógica de conexión y las operaciones básicas con la base de datos, utilizando la biblioteca psycopg2 para la interacción con PostgreSQL.

classDiagram
    class DatabaseConnection {
        -connection: psycopg2.connection
        -cursor: psycopg2.cursor
        -config: dict
        +init(database, user, password, host, port)
        -_conectar() : void
        -_validar_conexion_activa() : void
        +manejar_cursor()  : contextmanager
        +ejecutar_consulta(consulta, valores) : void
        +obtener_datos(consulta, valores) : list
        +cerrar_conexion() : void
    }
    class psycopg2 {
        +OperationalError
        +DatabaseError
        +connect()
    }

    DatabaseConnection "usa" --> psycopg2
Loading

🔸 Atributos Clave:

  • connection : Objeto de conexión con la base de datos (psycopg2.connection).

  • cursor: Objeto cursor para ejecutar consultas (psycopg2.cursor).

  • config: Diccionario que almacena los parámetros de configuración de la conexión.

🔸 Métodos Clave:

  • __init__(self, database, user, password, host, port): Constructor de la clase, inicializa la configuración de la conexión.

  • _conectar(self): Método privado para establecer la conexión inicial con la base de datos y obtener un cursor.

  • _validar_conexion_activa(self): Método privado para verificar la salud de la conexión y reconectar si es necesario.

  • manejar_cursor(self): Gestor de contexto (contextmanager) para operaciones transaccionales y gestión automática del cursor.

  • ejecutar_consulta(self, consulta, valores): Ejecuta consultas SQL que no devuelven resultados (INSERT, UPDATE, DELETE).

  • obtener_datos(self, consulta, valores): Ejecuta consultas SQL que devuelven resultados (SELECT).

  • cerrar_conexion(self): Cierra de forma segura la conexión y el cursor de la base de datos.


3. Gestión del Ciclo de Vida de la Conexión

Esta sección abarca el manejo completo de la conexión a la base de datos, desde el establecimiento inicial hasta la limpieza final de recursos, proporcionando una visión integral del ciclo de vida de la conexión en el sistema Capybara Films.

🔸 Establecimiento de la Conexión

La clase DatabaseConnection se inicializa automáticamente con los parámetros de conexión a PostgreSQL alojado en Railway. La configuración se almacena en un diccionario que incluye todos los parámetros necesarios para la conexión.

El proceso de conexión se ejecuta automáticamente durante la inicialización de la clase: DatabaseConnection.py:25-26

🔸 Validación y Recuperación de Conexión

El sistema implementa un mecanismo robusto de validación de conexión que verifica automáticamente el estado de la conexión antes de cada operación: DatabaseConnection.py:40-46

Características de la validación:

  • Detección automática de conexiones cerradas
  • Reconexión transparente sin intervención del usuario
  • Recreación del cursor cuando es necesario
  • Logging informativo del proceso de reconexión

🔸 Gestión de Cursores y Contexto Transaccional

La gestión de cursores se realiza a través del gestor de contexto manejar_cursor(), que proporciona manejo automático de transacciones y limpieza de recursos: DatabaseConnection.py:48-60

Funcionalidades del gestor de contexto:

  • Validación automática de conexión antes de cada operación
  • Commit automático en operaciones exitosas
  • Rollback automático en caso de excepciones
  • Recreación del cursor después de cada operación DatabaseConnection.py:59-60

Recreación Automática del Cursor

Una característica importante del gestor de contexto es que el cursor se recrea automáticamente después de cada operación. Esto asegura que cada operación de base de datos tenga un cursor limpio y evita problemas de estado entre transacciones consecutivas.

Beneficios de la recreación automática:

  • Previene conflictos de estado entre operaciones
  • Garantiza que cada transacción tenga un cursor fresco
  • Mejora la robustez del sistema ante errores de cursor

🔸 Limpieza y Cierre de Recursos

El método cerrar_conexion() proporciona una limpieza segura y completa de todos los recursos de base de datos:

Proceso de limpieza:

  1. Cierre seguro del cursor con manejo de excepciones.
  2. Cierre de la conexión principal.
  3. Logging de confirmación de cierre exitoso.
  4. Manejo de errores durante el proceso de limpieza.

🔸 Integración con el Sistema

La clase DatabaseConnection se integra con toda la arquitectura del sistema a través del patrón de inyección de dependencias. Una sola instancia de conexión es compartida entre todos los DAOs del sistema: main.py:20-26

Patrón de uso en DAOs:

  • Cada DAO recibe una instancia de DatabaseConnection en su constructor
  • Los DAOs utilizan los métodos ejecutar_consulta() y obtener_datos() para interactuar con la base de datos
  • El manejo de transacciones y conexiones es transparente para los DAOs

🔸 Beneficios del Diseño

Esta arquitectura de gestión del ciclo de vida proporciona:

  • Resiliencia: Reconexión automática ante fallos de conexión
  • Consistencia: Manejo transaccional automático con commit/rollback
  • Eficiencia: Reutilización de conexiones y cursores
  • Simplicidad: Interfaz transparente para los DAOs
  • Robustez: Manejo integral de errores y limpieza de recursos

El diseño asegura que todas las operaciones de base de datos en el sistema Capybara Films sean confiables, eficientes y mantengan la integridad de los datos a través de un manejo automático y transparente del ciclo de vida de la conexión.

4. Manejo de Transacciones

La gestión de transacciones se implementa a través del gestor de contexto manejar_cursor(), que proporciona funcionalidad de commit/rollback automático. Esto asegura la consistencia de los datos en todas las operaciones de la base de datos.

🔸 Patrón de Gestión de Transacciones

graph TD
    Inicio[Inicio de Transacción] --> Validar[validar_conexion_activa]
    Validar --> Cursor[cursor = connection.cursor]
    Cursor --> Yield[yield cursor]
    Yield --> Ejecutar[Ejecutar SQL]

    Ejecutar -- "Excepción?" --> ExceptionCheck{Excepción?}
    ExceptionCheck -- "Sí" --> Rollback[connection.rollback]
    ExceptionCheck -- "No" --> Commit[connection.commit]

    Rollback --> Raise[raise exception]
    Raise --> CerrarCursor[cursor.close]
    Commit --> CerrarCursor

    CerrarCursor --> Fin[Fin de Transacción]

Loading

El gestor de contexto CapybaraFilms/data/DatabaseConnection.py:48-60 maneja el ciclo de vida completo de la transacción, incluyendo el rollback automático en caso de excepciones y la gestión del cursor para operaciones subsiguientes.


5. Interfaz de Ejecución de Consultas

La clase DatabaseConnection proporciona dos métodos principales para las operaciones de base de datos:

🔸 Ejecución de Comandos (ejecutar_consulta)

  • Propósito: Se utiliza para operaciones INSERT, UPDATE, DELETE y otras operaciones que no devuelven resultados.

  • Comportamiento: Este método maneja automáticamente la gestión de transacciones y el registro de errores.

# Firma del método desde DatabaseConnection.py:62-75
def ejecutar_consulta(self, consulta, valores=None)

🔸 Recuperación de Datos (obtener_datos)

  • Propósito: Se utiliza para consultas SELECT que devuelven conjuntos de resultados.

  • Comportamiento: Este método devuelve una lista de tuplas que representan los resultados de la consulta.

# Firma del método desde DatabaseConnection.py:77-91
def obtener_datos(self, consulta, valores=None)

Ambos métodos utilizan consultas parametrizadas para prevenir la inyección de SQL y aprovechan el gestor de contexto manejar_cursor() para garantizar la seguridad transaccional.


6. Ejemplos de Uso de DatabaseConnection en los DAOs

Aquí tienes ejemplos prácticos de cómo los diferentes DAOs utilizan DatabaseConnection en el sistema Capybara Films:

🔹 Ejemplo 1: Búsqueda de Cliente por DNI

# Ejemplo de uso en ClienteDAO - Búsqueda por DNI  
def buscar_por_dni(self, dni: str):  
    try:  
        sentencia = "SELECT id_cliente, dni, nombre, apellido, email FROM cliente WHERE dni = %s"  
        resultado = self.db.obtener_datos(sentencia, (dni,))  
        if resultado:  
            fila = resultado[0]  
            return Cliente(fila[0], fila[1], fila[2], fila[3], fila[4])  
        return None

Fuente: ClienteDAO.py:42-48

🔹 Ejemplo 2: Creación de Cliente con Validación

# Ejemplo de uso en ClienteDAO - Inserción de datos  
sentencia = """  
INSERT INTO cliente (dni, nombre, apellido, email)  
VALUES (%s, %s, %s, %s)  
RETURNING id_cliente  
"""  
valores = (cliente.dni, cliente.nombre, cliente.apellido, cliente.email)  
self.db.ejecutar_consulta(sentencia, valores)

Fuente: ClienteDAO.py:26-32

🔹 Ejemplo 3: Búsqueda de Butacas por Sala

# Ejemplo de uso en ButacaDAO - Consulta con parámetros  
def butacas_por_sala(self, id_sala: int):  
    try:  
        sentencia = "SELECT id_butaca, fila, columna, categoria, estado FROM butaca WHERE id_sala = %s"  
        resultado = self.db.obtener_datos(sentencia, (id_sala,))  
        return [Butaca(fila[0], fila[1], fila[2], fila[3], fila[4]) for fila in resultado]

🔹 Ejemplo 4: Actualización de Estado de Butaca

# Ejemplo de uso en ButacaDAO - Actualización de datos  
def actualizar_estado(self, id_butaca: int, estado: bool):  
    try:  
        sentencia = "UPDATE butaca SET estado = %s WHERE id_butaca = %s"  
        self.db.ejecutar_consulta(sentencia, (estado, id_butaca))

🔹 Ejemplo 5: Creación de Reserva con Transacciones Complejas

# Ejemplo de uso en ReservaDAO - Inserción con RETURNING  
sentencia = """  
INSERT INTO reserva (id_cliente, id_sala, fecha_hora)  
VALUES (%s, %s, NOW())  
RETURNING id_reserva  
"""  
valores = (id_cliente, id_sala)  
resultado = self.db.obtener_datos(sentencia, valores)

🔹 Ejemplo 6: Búsqueda de Salas por Película

# Ejemplo de uso en SalaDAO - Consulta con filtro  
def buscar_por_pelicula(self, id_pelicula: int):  
    try:  
        sentencia = "SELECT id_sala, id_pelicula FROM sala WHERE id_pelicula = %s"  
        resultado = self.db.obtener_datos(sentencia, (id_pelicula,))

🔸 Características Comunes en el Uso

  1. Consultas Parametrizadas: Todos los DAOs utilizan parámetros (%s) para prevenir inyección SQL.

  2. Manejo de Excepciones: Cada DAO implementa bloques try-except para capturar errores de base de datos.

  3. Construcción de Entidades: Los resultados se convierten automáticamente en objetos de dominio usando desempaquetado de tuplas.

  4. Dos Métodos Principales:

  • obtener_datos(): Para consultas SELECT que devuelven resultados
  • ejecutar_consulta(): Para operaciones INSERT, UPDATE, DELETE

Estos ejemplos demuestran cómo DatabaseConnection proporciona una interfaz consistente y segura para todas las operaciones de base de datos en el sistema.


7. Manejo de Errores y Recuperación

El sistema implementa un manejo de errores integral para las operaciones de base de datos, con manejo específico para diferentes tipos de excepciones de base de datos:

Tipo de Excepción Estrategia de Manejo Ubicación del Código
OperationalError Registrar error, intentar reconexión DatabaseConnection.py:34-38
DatabaseConnection.py:70-71
DatabaseError Registrar error, hacer rollback de la transacción DatabaseConnection.py:72-73
Generic Exception Registrar error, volver a lanzar para que el llamador lo maneje DatabaseConnection.py:74-75
DatabaseConnection.py:89-91

El manejo de errores asegura que:

  • Las fallas de conexión activan intentos automáticos de reconexión.

  • Los errores de la base de datos resultan en un rollback de la transacción.

  • Todos los errores se registran con mensajes descriptivos.

  • Las excepciones se propagan correctamente al código que las invocó.


8. Integración con la Arquitectura del Sistema

La clase DatabaseConnection actúa como el componente central de infraestructura en la arquitectura del sistema Capybara Films, proporcionando conectividad unificada a la base de datos para toda la capa de acceso a datos.

🔸 Patrón de Inyección de Dependencias

El sistema implementa un patrón de inyección de dependencias donde una sola instancia de DatabaseConnection es compartida entre todos los DAOs del sistema:

# Inicialización centralizada en main.py  [header-3](#header-3)
db_connection = DatabaseConnection()  
cliente_dao = ClienteDAO(db_connection)  
pelicula_dao = PeliculaDAO(db_connection)  
sala_dao = SalaDAO(db_connection)  
butaca_dao = ButacaDAO(db_connection)  
reserva_dao = ReservaDAO(db_connection)  
candy_dao = CandyDAO(db_connection)

🔸 Beneficios Arquitecturales

  • Centralización de Recursos: Una sola conexión compartida optimiza el uso de recursos de base de datos y simplifica la gestión de conexiones.

  • Consistencia Transaccional: Todos los DAOs utilizan la misma infraestructura de transacciones, garantizando comportamiento uniforme.

  • Mantenibilidad: Los cambios en la lógica de conexión se centralizan en una sola clase, facilitando el mantenimiento.

  • Escalabilidad: El diseño permite futuras optimizaciones como pooling de conexiones sin afectar los DAOs existentes.

Esta integración asegura que DatabaseConnection sirva como la base sólida sobre la cual se construye toda la funcionalidad de persistencia del sistema de gestión de cine.


⬆️ Volver arriba
⚠️ **GitHub.com Fallback** ⚠️