Saltar a contenido

Sources (Adaptadores de Lectura)

Los sources son adaptadores que leen datos de sistemas externos. Actualmente hay dos tipos implementados.

Tipos de Sources

classDiagram
    class SourceAdapter {
        <<interface>>
        +name: string
        +connect(): Promise~void~
        +getData(entity, options): Promise~RowData[]~
        +fetchOne(entity, pk): Promise~RowData|null~
        +getPrimaryKey(entity): string[]
        +supports(entity): boolean
        +close(): Promise~void~
    }

    class MssqlSourceAdapter {
        -pool: ConnectionPool
        -entities: Record
        +connect()
        +getData()
        +fetchOne()
    }

    class HttpSourceAdapter {
        -config: HttpConfig
        -entities: Record
        +connect()
        +getData()
        +fetchOne()
    }

    SourceAdapter <|.. MssqlSourceAdapter
    SourceAdapter <|.. HttpSourceAdapter

MSSQL Source

Lee datos de SQL Server (Tango).

Configuración

// src/config/sources/tango.ts
export const tangoSource: MssqlSourceConfig = {
  name: 'tango',
  type: 'mssql-source',
  config: {
    server: process.env.MSSQL_SERVER || 'localhost',
    port: parseInt(process.env.MSSQL_PORT || '1433'),
    database: process.env.MSSQL_DATABASE || 'tango',
    user: process.env.MSSQL_USER || 'sa',
    password: process.env.MSSQL_PASSWORD || '',
  },
  entities: {
    articulos: {
      table: 'WEBVIEW',
      primaryKey: ['CODIGO'],
    },
    clientes: {
      table: 'WEBCLIENTE',
      primaryKey: ['Cod Cliente'],
    },
    pedidos: {
      table: 'WMS_Pedidos',
      primaryKey: ['Nro. Pedido'],
    },
    // ... más entities
  },
};

Entity Config

Propiedad Tipo Descripción
table string Nombre de la tabla/vista
primaryKey string[] Campos que forman la PK
condition string? WHERE adicional
join string? JOINs adicionales
staticData RowData[]? Datos estáticos (sin query)

Ejemplo con Condición

proveedores: {
  table: 'CPA01',
  condition: 'HABILITADO = 1',
  primaryKey: ['COD_PROVEE'],
}

Ejemplo con Datos Estáticos

categorias: {
  table: '__STATIC__',
  primaryKey: ['codigo'],
  staticData: [
    { codigo: '99', descripcion: 'SIN CATEGORÍA', titulo: 'SIN CATEGORÍA' }
  ],
}

HTTP Source

Lee datos de APIs REST (ej: WMS).

Configuración

// src/config/sources/wms-source.ts
export const wmsSource: HttpSourceConfig = {
  name: 'wms-source',
  type: 'http-source',
  config: {
    baseUrl: process.env.WMS_API_URL || 'http://localhost:8888',
    timeout: 30000,
    headers: {
      'X-API-KEY': process.env.WMS_API_KEY || '',
    },
  },
  entities: {
    pedidosPreparados: {
      endpoint: 'pedidos/preparados',
      dateField: 'fechaNovedad',
      responsePath: '[0]',
      primaryKey: ['idERP'],
      queryParams: {
        sin_sincronizar: 1,
      },
    },
  },
};

Entity Config HTTP

Propiedad Tipo Descripción
endpoint string Path del endpoint
primaryKey string[] Campos que forman la PK
dateField string? Campo para filtro incremental
responsePath string? Path para extraer datos (ej: [0], data.items)
queryParams Record? Query params adicionales

Response Path

Permite extraer datos de respuestas anidadas:

// Respuesta: [[{...}, {...}]]
responsePath: '[0]'  // Extrae el primer array

// Respuesta: { data: { items: [...] } }
responsePath: 'data.items'

Múltiples Instancias

Para ambientes dev/prod, crear sources separados:

// tango.ts (producción)
export const tangoSource: MssqlSourceConfig = {
  name: 'tango',
  config: {
    server: process.env.MSSQL_SERVER,
    // ...
  },
  // ...
};

// tango-development.ts
export const tangoDevelopmentSource: MssqlSourceConfig = {
  name: 'tango-development',
  config: {
    server: process.env.MSSQL_DEVELOPMENT_SERVER,
    // ...
  },
  entities: {
    'articulos-dev': { table: 'WEBVIEW', ... },
    'clientes-dev': { table: 'WEBCLIENTE', ... },
  },
};

Pool de Conexiones

Cada source MSSQL debe usar new sql.ConnectionPool() en lugar de sql.connect() para evitar compartir conexiones entre instancias.

// ✅ Correcto
this.pool = new sql.ConnectionPool(config);
await this.pool.connect();

// ❌ Incorrecto (pool global compartido)
this.pool = await sql.connect(config);

Agregar Nuevo Source

  1. Crear archivo de configuración en src/config/sources/
  2. Exportar en src/config/sources/index.ts
  3. El registry lo detecta automáticamente por el type
// Nuevo source MySQL (ejemplo)
export const mysqlSource: MysqlSourceConfig = {
  name: 'mysql-source',
  type: 'mysql-source',  // Requiere implementar MysqlSourceAdapter
  config: { ... },
  entities: { ... },
};