feat(ServiceFactory): Criação de importação de classes de forma dinâmica mais otimizada
This commit is contained in:
parent
2223db9d75
commit
433d889060
4 changed files with 86 additions and 26 deletions
64
actions/dynamic_import/service_factory.py
Normal file
64
actions/dynamic_import/service_factory.py
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
import importlib
|
||||||
|
import re
|
||||||
|
from functools import lru_cache
|
||||||
|
from typing import Type, TypeVar, Optional
|
||||||
|
from actions.config.config import Config
|
||||||
|
from actions.env.env_config_loader import EnvConfigLoader
|
||||||
|
|
||||||
|
# Genérico para garantir que o retorno respeite o Protocolo
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceFactory:
|
||||||
|
|
||||||
|
def __init__(self, package: str, table: str):
|
||||||
|
|
||||||
|
# Instancia o loader com o prefixo correto
|
||||||
|
env = EnvConfigLoader(".env")
|
||||||
|
|
||||||
|
# Ex: "packages.v1"
|
||||||
|
self.base_root = "packages.v1"
|
||||||
|
self.package = package
|
||||||
|
self.table = table
|
||||||
|
|
||||||
|
# Carrega config apenas uma vez
|
||||||
|
self.app_config = Config.get("app.json")
|
||||||
|
|
||||||
|
# Define a UF da aplicação
|
||||||
|
self.current_state = env.ORIUS_CLIENT_STATE
|
||||||
|
|
||||||
|
@lru_cache(maxsize=32)
|
||||||
|
def make(self, class_name: str, interface: Type[T]) -> T:
|
||||||
|
"""
|
||||||
|
Instancia um serviço dinamicamente com comportamento de Autoload.
|
||||||
|
"""
|
||||||
|
# 1. Converte CamelCase para snake_case (Autoload style)
|
||||||
|
# Ex: TAtoIndexService -> t_ato_index_service
|
||||||
|
module_name = re.sub(r"(?<!^)(?=[A-Z])", "_", class_name).lower()
|
||||||
|
|
||||||
|
# 2. Monta o caminho completo
|
||||||
|
# Ex: packages.v1.servicos.balcao.services.t_ato.SP.t_ato_index_service
|
||||||
|
import_path = (
|
||||||
|
f"{self.base_root}.{self.package}.services."
|
||||||
|
f"{self.table}.{self.current_state}.{module_name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 3. Importação Dinâmica
|
||||||
|
module = importlib.import_module(import_path)
|
||||||
|
|
||||||
|
# 4. Pega a classe do módulo
|
||||||
|
clazz = getattr(module, class_name)
|
||||||
|
|
||||||
|
# 5. Retorna a INSTÂNCIA da classe (já com () )
|
||||||
|
# Se seus serviços precisam de argumentos no __init__, altere aqui.
|
||||||
|
return clazz()
|
||||||
|
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(
|
||||||
|
f"FATAL: Não foi possível carregar o serviço '{class_name}' para o estado '{self.current_state}'.\nCaminho tentado: {import_path}\nErro: {e}"
|
||||||
|
)
|
||||||
|
except AttributeError:
|
||||||
|
raise AttributeError(
|
||||||
|
f"FATAL: O arquivo '{module_name}.py' existe, mas a classe '{class_name}' não foi encontrada dentro dele."
|
||||||
|
)
|
||||||
10
interfaces/service_protocols.py
Normal file
10
interfaces/service_protocols.py
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
from typing import Protocol, Any, runtime_checkable
|
||||||
|
|
||||||
|
|
||||||
|
@runtime_checkable
|
||||||
|
class ServiceProtocolsInterface(Protocol):
|
||||||
|
"""
|
||||||
|
Contrato que garante que todo serviço tenha um método execute.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def execute(self, schema: Any) -> Any: ...
|
||||||
|
|
@ -1,34 +1,20 @@
|
||||||
from actions.dynamic_import.dynamic_import import DynamicImport
|
from actions.dynamic_import.service_factory import ServiceFactory
|
||||||
from packages.v1.servicos.balcao.schemas.t_ato_schema import TAtoIndexSchema
|
from interfaces.service_protocols import ServiceProtocolsInterface
|
||||||
from packages.v1.servicos.balcao.services.t_ato.t_ato_index_service import (
|
|
||||||
TAtoIndexService,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TAtoController:
|
class TAtoController:
|
||||||
"""
|
|
||||||
Controller responsável por orquestrar as operações CRUD da tabela T_PESSOA_CARTAO,
|
|
||||||
utilizando carregamento dinâmico de serviços via DynamicImport.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# ----------------------------------------------------
|
|
||||||
# Inicialização do DynamicImport
|
|
||||||
# ----------------------------------------------------
|
|
||||||
self.dynamic_import = DynamicImport()
|
|
||||||
self.dynamic_import.set_package("servicos.balcao")
|
|
||||||
self.dynamic_import.set_table("t_ato")
|
|
||||||
|
|
||||||
# ----------------------------------------------------
|
# Configura o escopo deste controller
|
||||||
# Lista todos os registros de T_PESSOA_CARTAO
|
self.factory = ServiceFactory(package="servicos.balcao", table="t_ato")
|
||||||
# ----------------------------------------------------
|
|
||||||
def index(self, t_ato_index_schema: TAtoIndexSchema):
|
|
||||||
|
|
||||||
# Instância da classe service
|
def index(self, schema):
|
||||||
self.index_service = TAtoIndexService()
|
|
||||||
|
|
||||||
# Execução da listagem
|
# Instânciamento da classe
|
||||||
return {
|
service = self.factory.make("TAtoIndexService", ServiceProtocolsInterface)
|
||||||
"message": "Registros de T_ATO localizados com sucesso.",
|
|
||||||
"data": self.index_service.execute(t_ato_index_schema),
|
# O VS Code sabe que .execute() existe por causa do IService!
|
||||||
}
|
result = service.execute(schema)
|
||||||
|
|
||||||
|
return {"message": "Sucesso", "data": result}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue