---
name: fluig-datasets
description: “Datasets customizados Fluig — JDBC, REST, ServiceManager, compostos e internos. Use quando precisar consultar banco de dados, criar dataset, consumir webservice via dataset ou combinar dados de multiplas fontes. Ativa com: 'criar dataset', 'consultar banco', 'dataset JDBC', 'dataset composto', 'inserir dados SQL'.”
license: MIT
metadata:
  author: Nevoa
  version: "1.0.0"
  category: development
  platform: totvs-fluig
---

# Skill: Datasets Customizados Fluig

Gera datasets customizados para consultar, inserir e transformar dados no Fluig.

## Tipos de Dataset

| Tipo | Uso | Exemplo |
|---|---|---|
| **Interno** | Dados estaticos ou config | Servidores, parametros |
| **JDBC** | Consulta SQL direta | Tabelas Fluig, RM, Protheus |
| **ServiceManager** | WebService SOAP/REST registrado | ExecBO Datasul, APIs |
| **Composto** | Chama outros datasets | Combinar dados de varias fontes |
| **INSERT/UPDATE** | Grava dados via SQL | Integracao bidirecional |

## Assinatura Padrao

```javascript
function createDataset(fields, constraints, sortFields) {
    // fields = colunas solicitadas (array ou null)
    // constraints = filtros passados pelo chamador
    // sortFields = ordenacao solicitada
    //
    // DEVE retornar um DatasetBuilder
    var dataset = DatasetBuilder.newDataset();
    dataset.addColumn("coluna1");
    dataset.addColumn("coluna2");
    dataset.addRow(new Array("valor1", "valor2"));
    return dataset;
}
```

## Como Ler Constraints (Filtros)

```javascript
// Constraints sao passados pelo chamador:
// DatasetFactory.createConstraint("campo", "valor", "valor", ConstraintType.MUST)

// Padrao para ler constraints:
var meuFiltro = "";
if (constraints != null) {
    for (var i = 0; i < constraints.length; i++) {
        if (constraints[i].fieldName == "meuCampo") {
            meuFiltro = constraints[i].initialValue;
        }
    }
}
```

## Como Chamar Datasets

```javascript
// De qualquer evento server-side:
var c1 = DatasetFactory.createConstraint("campo", "valor", "valor", ConstraintType.MUST);
var ds = DatasetFactory.getDataset("nomeDataset", null, new Array(c1), null);

// Ler resultado:
for (var i = 0; i < ds.rowsCount; i++) {
    var valor = ds.getValue(i, "nomeColuna");
}
```

## 1. Dataset Interno (Estatico)

### Quando Usar
- Configuracoes (servidor, porta, credenciais de servico)
- Listas fixas que mudam raramente
- Parametros de ambiente (producao vs teste)

### Padrao
```javascript
function createDataset(fields, constraints, sortFields) {
    var ds = DatasetBuilder.newDataset();
    ds.addColumn("server");
    ds.addColumn("port");

    // PRODUCAO
    ds.addRow(new Array("172.22.52.100", "80"));

    // TESTE (comentado)
    // ds.addRow(new Array("172.20.10.41", "8080"));

    return ds;
}
```

## 2. Dataset JDBC (SQL Direto)

### Quando Usar
- Consultar tabelas do banco Fluig
- Consultar bancos externos (RM, Protheus) via JNDI
- Queries complexas com JOINs e subqueries

### Padrao de Producao (Generico com colunas dinamicas)
```javascript
function createDataset(fields, constraints, sortFields) {
    var ds = DatasetBuilder.newDataset();
    var sql = "SELECT col1, col2 FROM tabela WHERE ativo = 'S'";
    var dataSource = "/jdbc/FluigDSRO";

    var ic = new javax.naming.InitialContext();
    var dsJndi = ic.lookup(dataSource);
    var created = false;

    try {
        var conn = dsJndi.getConnection();
        var stmt = conn.createStatement();
        var rs = stmt.executeQuery(sql);
        var columnCount = rs.getMetaData().getColumnCount();

        while (rs.next()) {
            if (!created) {
                for (var i = 1; i <= columnCount; i++) {
                    ds.addColumn(rs.getMetaData().getColumnName(i));
                }
                created = true;
            }
            var arr = new Array();
            for (var i = 1; i <= columnCount; i++) {
                var obj = rs.getObject(rs.getMetaData().getColumnName(i));
                arr[i - 1] = (obj != null) ? obj.toString() : "null";
            }
            ds.addRow(arr);
        }
    } catch (e) {
        log.error("ERRO JDBC: " + e.message);
    } finally {
        if (rs != null) rs.close();
        if (stmt != null) stmt.close();
        if (conn != null) conn.close();
    }

    return ds;
}
```

### DataSources Comuns
- `/jdbc/FluigDSRO` â€” Banco Fluig (somente leitura)
- `/jdbc/FluigDS` â€” Banco Fluig (leitura/escrita)
- `java:/jdbc/CorporeRM` â€” Banco RM/TOTVS
- JNDI customizado cadastrado no servidor

## 3. Dataset ServiceManager (WebService)

### Quando Usar
- Chamar APIs SOAP/REST cadastradas no Painel do Fluig
- Integrar com Datasul ExecBO
- Chamar servicos TOTVS registrados

### Padrao de Producao (ExecBO Datasul)
```javascript
function createDataset(fields, constraints, sortFields) {
    var ds = DatasetBuilder.newDataset();
    ds.addColumn("response");

    var programName = constraintValue(constraints, "programName");
    var procedureName = constraintValue(constraints, "procedureName");
    var jsonParams = constraintValue(constraints, "json");

    try {
        var serviceProvider = ServiceManager.getService("WSEXECBO");
        var serviceLocator = serviceProvider.instantiate(
            "com.totvs.framework.ws.execbo.service.WebServiceExecBO");
        var service = serviceLocator.getWebServiceExecBOPort();

        var token = service.userLogin("fluig-integr");
        var resp = service.callProcedureWithToken(
            token, programName, procedureName, jsonParams);

        ds.addRow(new Array(resp));
    } catch (e) {
        log.error("Erro ServiceManager: " + e.message);
        ds.addColumn("msgErro");
        ds.addRow(new Array("ERRO", e.message));
    }

    return ds;
}

function constraintValue(constraints, campo) {
    for (var i = 0; i < constraints.length; i++) {
        if (constraints[i].getFieldName().equals(campo)) {
            return constraints[i].getInitialValue();
        }
    }
    return "";
}
```

## 4. Dataset Composto (Chama outros datasets)

### Quando Usar
- Combinar dados de multiplas fontes
- Navegar pela estrutura do Fluig (processo -> formulario -> dados)
- Enricher dados com lookups adicionais

### Padrao de Producao
```javascript
function createDataset(fields, constraints, sortFields) {
    var ds = DatasetBuilder.newDataset();
    ds.addColumn("processo");
    ds.addColumn("solicitante");
    ds.addColumn("departamento");

    // Buscar dados do processo
    var c1 = DatasetFactory.createConstraint(
        "workflowProcessPK.processInstanceId", numProcesso, numProcesso, ConstraintType.MUST);
    var dsProcesso = DatasetFactory.getDataset("workflowProcess", null, new Array(c1), null);

    if (dsProcesso.rowsCount > 0) {
        var cardDocId = dsProcesso.getValue(0, "cardDocumentId");

        // Buscar dados do formulario
        var c2 = DatasetFactory.createConstraint("metadata#id", cardDocId, cardDocId, ConstraintType.MUST);
        var dsForm = DatasetFactory.getDataset("nomeDatasetFormulario", null, new Array(c2), null);

        if (dsForm.rowsCount > 0) {
            ds.addRow(new Array(
                numProcesso,
                dsForm.getValue(0, "solicitante"),
                dsForm.getValue(0, "departamento")
            ));
        }
    }

    return ds;
}
```

## 5. Dataset de INSERT/UPDATE

### Quando Usar
- Gravar dados no banco externo (RM, Protheus)
- Chamado pelo afterSaveNew ou afterTaskComplete

### Padrao de Producao (CELI)
```javascript
function createDataset(fields, constraints, sortFields) {
    var jndiName = "java:/jdbc/CorporeRM";

    try {
        var campo1 = constraints[0].initialValue;
        var campo2 = constraints[1].initialValue;

        var sql = "INSERT INTO tabela (col1, col2) VALUES ('" + campo1 + "', '" + campo2 + "')";

        log.info("INSERT SQL: " + sql);
        var dsResult = DatasetFactory.getDataset("dsSQL", new Array(sql, jndiName), null, null);
        return dsResult;
    } catch (e) {
        log.error("Erro INSERT: " + e.message);
        throw e.message;
    }
}
```

### AVISO DE SEGURANCA
O padrao acima com concatenacao de SQL e INSEGURO (SQL injection).
Para producao, prefira PreparedStatement:

```javascript
var pstmt = conn.prepareStatement("INSERT INTO tabela (col1, col2) VALUES (?, ?)");
pstmt.setString(1, campo1);
pstmt.setString(2, campo2);
pstmt.executeUpdate();
```

## 6. Dataset Generico SQL (Helper)

### Quando Usar
- Reutilizar em multiplos datasets de INSERT/UPDATE
- Recebe SQL e dataSource via fields[]

### Padrao de Producao (dsSQL)
```javascript
function createDataset(fields, constraints, sortFields) {
    var sql = fields[0];
    var dataSource = fields[1];

    // ... executa SQL generico (ver template)
}
```

## Datasets Internos do Fluig

Built-in: `colleague`, `workflowProcess`, `processHistory`, `processTask`, `processState`, `processDefinition`, `document`.

> Tabela completa com colunas e exemplos: [references/datasources-e-apis.md](./references/datasources-e-apis.md)

## Regras

- MUST: ES5 obrigatorio (roda no servidor)
- MUST: Fechar conexoes JDBC em bloco finally (rs, stmt, conn)
- MUST: try/catch em toda operacao externa
- MUST: Logar erros com log.error()
- MUST: Usar PreparedStatement para INSERT/UPDATE com dados do usuario
- SHOULD: Usar InitialContext + JNDI lookup para conexoes
- SHOULD: Retornar dataset vazio (nao null) em caso de erro
- MUST NOT: Hardcodar credenciais no codigo
- MUST NOT: Deixar conexoes abertas (memory leak)

## Checklist de Geracao

- [ ] Funcao createDataset com assinatura correta
- [ ] DatasetBuilder.newDataset() + addColumn + addRow
- [ ] Leitura de constraints para filtros
- [ ] Conexao JDBC com try/catch/finally
- [ ] PreparedStatement para queries com parametros
- [ ] Log de erros
- [ ] Retorno consistente (nunca null)

## Prompts Estrategicos Disponiveis

- `criar-dataset-jdbc-seguro-constraints.md` - Dataset JDBC seguro com constraints e boas praticas.
- `refatorar-dataset-legado-sql-inseguro.md` - Refatoracao de dataset legado com SQL inseguro.
- `criar-dataset-composto-enriquecedor.md` - Dataset composto com enriquecimento por datasets internos/customizados.
- `implementar-diagnosticar-dataset-sincronizado-onsync.md` - Implementacao/diagnostico de dataset sincronizado (`onSync`).

Use estes prompts para cobrir criacao, hardening, composicao e sincronizacao de datasets.
## Skills Relacionadas

- [fluig-integracoes](../fluig-integracoes/SKILL.md) — REST, SOAP, datasets sincronizados (onSync)
- [fluig-eventos-formulario](../fluig-eventos-formulario/SKILL.md) — afterSaveNew chama datasets de integracao
- [fluig-eventos-processo](../fluig-eventos-processo/SKILL.md) — Eventos de workflow que consomem datasets

## Templates Disponiveis
- [dataset-jdbc-base.js](./templates/dataset-jdbc-base.js) â€” Query SQL com JNDI e colunas dinamicas
- [dataset-servicemanager-base.js](./templates/dataset-servicemanager-base.js) â€” WebService via ServiceManager
- [dataset-composto-base.js](./templates/dataset-composto-base.js) â€” Combina multiplos datasets
- [dataset-interno-base.js](./templates/dataset-interno-base.js) â€” Dados estaticos/config

## Recursos Adicionais
- Para templates base, consulte os arquivos em [templates/](./templates/)
- Para exemplos de implementaÃ§Ã£o real, consulte [examples/](./examples/)
### Exemplos recomendados
- [exemplo_01_dataset_sincronizado_rest_onSync](./examples/exemplo_01_dataset_sincronizado_rest_onSync/): dataset sincronizado com `defineStructure` + `onSync` e consumo REST.
- [exemplo_02_dataset_jdbc_wrapper_legacy_constraints](./examples/exemplo_02_dataset_jdbc_wrapper_legacy_constraints/): exemplo legado com constraints para estudo de refatoracao e hardening.
- Para referÃªncia tÃ©cnica detalhada, consulte [references/](./references/)

---

## Curadoria de Contexto Local

Para buscar exemplos reais no acervo local `Contexto`, consulte [references/contexto-curadoria.md](./references/contexto-curadoria.md).
Abra essa referencia quando a tarefa exigir aderencia a legado/producao ou comparacao com implementacoes existentes.
