![Firebird Logo](https://www.studioserver.com.br/index_arquivos/firebird-logo.png)

# Cliente JavaScript/Typescrypt para Node.js de acesso a banco de dados Firebird charset ISO8859_1 e e UTF8.

## Instalação

```bash
npm install limber-firebird-client -s
```

## Utilização

```js
const express = require("express");
const firebird = require("limber-firebird-client");

const app = express();
app.use(firebird.databaseParser());

```

### Parâmetros .env
- `FIREBIRD_DISPLAY_LOGS` - Se o valor for `true` exibe todos os logs da conexão. 
- `FIREBIRD_CONN_FORCE_CLEAR` - Se `true` define para limpar as conexões não usadas do pool a cada intervalo definido pela opção `FIREBIRD_CONN_TIMEOUT_CLEAR` ou se `false` após o tempo máximo definido pela opção `FIREBIRD_CONN_TIMEOUT_CLEAR` após a última requisição. 
- `FIREBIRD_CONN_TIMEOUT_CLEAR` - Define o tempo máximo em milissegundos para limpar as conexões do pool.
- `FIREBIRD_ENCODING` - Define o encoding para strings `utf8` ou `latin1`.
- `FIREBIRD_MAX_CONN` - Define o número máximo de conexões simultaneas via pool. 
- `FIREBIRD_HOST` - Informa o host de acesso ao serviço do banco de dados. 
- `FIREBIRD_PORT` - Informa a porta de acesso ao serviço do banco de dados. 
- `FIREBIRD_BASE` - Informa o caminho do arquivo do banco de dados. 
- `FIREBIRD_USER` - Usuário de acesso do banco de dados. 
- `FIREBIRD_PASSWD` - Senha de acesso do banco de dados. 
- `FIREBIRD_LOWERCASE_KEYS` - Retorna o nome das colunas em minúsculo. 
- `FIREBIRD_ROLE` - Informa a role do banco de dados. 
- `FIREBIRD_PAGE_SIZE` - Informa o tamanho da paginação do banco de dados. 
- `FIREBIRD_IMG_MAX_CONN` - Define para a base de imagens o número máximo de conexões simultaneas via pool. 
- `FIREBIRD_IMG_HOST` - Informa para a base de imagens o host de acesso ao serviço do banco de dados. 
- `FIREBIRD_IMG_PORT` - Informa para a base de imagens a porta de acesso ao serviço do banco de dados. 
- `FIREBIRD_IMG_BASE` - Informa para a base de imagens o caminho do arquivo do banco de dados. 
- `FIREBIRD_IMG_USER` - Usuário de acesso da base de imagens do banco de dados. 
- `FIREBIRD_IMG_PASSWD` - Senha de acesso da base de imagens do banco de dados. 
- `FIREBIRD_IMG_LOWERCASE_KEYS` - Retorna o nome das colunas em minúsculo para a base de imagens.
- `FIREBIRD_IMG_ROLE` - Informa a role do banco de dados de imagens. 
- `FIREBIRD_IMG_PAGE_SIZE` - Informa o tamanho da paginação do banco de dados de imagens.

Exemplo:
````dotenv
FIREBIRD_DISPLAY_LOGS=true
FIREBIRD_CONN_FORCE_CLEAR=false
FIREBIRD_CONN_TIMEOUT_CLEAR=1800000
FIREBIRD_ENCODING=utf8

FIREBIRD_MAX_CONN=5
FIREBIRD_HOST=127.0.0.1
FIREBIRD_PORT=3050
FIREBIRD_BASE=C:\Limber\DATA\CDE_WIN.FDB
FIREBIRD_USER=SYSDBA
FIREBIRD_PASSWD=masterkey
FIREBIRD_LOWERCASE_KEYS=false

FIREBIRD_IMG_MAX_CONN=5
FIREBIRD_IMG_HOST=127.0.0.1
FIREBIRD_IMG_PORT=3050
FIREBIRD_IMG_BASE=C:\Limber\DATA\CDE_WIN_IMAGENS.FDB
FIREBIRD_IMG_USER=SYSDBA
FIREBIRD_IMG_PASSWD=masterkey
FIREBIRD_IMG_LOWERCASE_KEYS=false
````

### Parâmetros padrões da biblioteca

- `DEFAULT_FIREBIRD_USER` - Usuário padrão de acesso ao banco de dados. 
- `DEFAULT_FIREBIRD_PASSWORD` - Senha padrão de acesso ao banco de dados. 
- `DEFAULT_FIREBIRD_HOST` - Host padrão de acesso ao banco de dados. 
- `DEFAULT_FIREBIRD_PORT` - Porta padrão de acesso ao banco de dados. 
- `DEFAULT_FIREBIRD_LOWERCASE_KEYS` - Definição padrão de retorno de colunas em minúsculo. 
- `DEFAULT_FIREBIRD_PAGE_SIZE` - Valor padrão do tamanho da paginação. 
- `DEFAULT_FIREBIRD_ROLE` - Valor padrão da role de conexão. 
- `DEFAULT_FIREBIRD_MAX_POOL_CONNECTION` - Numero padrão do máximo de conexões permitidas no pool. 
- `DEFAULT_FIREBIRD_TIMEOUT_DESTROY_POOLS` - Tempo padrão que define o tempo máximo em milissegundos para limpar as conexões do pool. 
- `DEFAULT_FIREBIRD_CONN_FORCE_CLEAR` - Valor padrão da forma de limpar as conexões do pool. 
- `DEFAULT_FIREBIRD_DISPLAY_LOGS` - Valor padrão se exibe os logs da biblioteca. 


### Métodos retornados pelo req.firebird

- `req.firebird.attachDataBase(options)` Realiza a conexão direta com o banco de dados e retorna um objeto do tipo [DirectDatabase](#DirectDatabase) para realização de consultas ou alterações 
- `req.firebird.openDataBaseRead()` Retorna um objeto do tipo [Database](#Database) apenas para realização de consultas no banco de dados
- `req.firebird.openDataBaseWrite(usuario)` Retorna um objeto do tipo [Transaction](#Transaction) para realizar alterações no banco de dados 
- `req.firebird.openDataBaseImageRead()` Retorna um objeto do tipo [Database](#Database) apenas para realização de consultas no banco de dados de imagens
- `req.firebird.openDataBaseImageWrite()` Retorna um objeto do tipo [Transaction](#Transaction) para realizar alterações no banco de dados de imagens 


### Métodos de conexão direta

- `firebird.attachDataBase(options)` Realiza a conexão direta com o banco de dados e retorna um objeto do tipo [DirectDatabase](#DirectDatabase) para realização de consultas ou alterações 
- `firebird.attachPool()` Retorna uma conexão disponível no pool do tipo [DirectDatabase](#DirectDatabase) para realização de consultas ou alterações 
- `firebird.attachPoolImage()` Retorna uma conexão disponível no pool de imagens do tipo [DirectDatabase](#DirectDatabase) para realização de consultas ou alterações 



### Options attachtDataBase

```js
let options = {};
options.host = '127.0.0.1';
options.port = 3050;
options.database = 'C:\\Limber\\DATA\\CDE_WIN.FDB';
options.user = 'SYSDBA';
options.password = 'masterkey';
options.lowercase_keys = false;
options.role = null;
options.pageSize = 4096;
options.encoding = 'utf8';

```

### Database

- `db.query(query, [params])` - Consulta clássica, retorna um Array of Object
- `db.queryOne(query, [params])` - Retorna o primeiro objeto da consulta ou null
- `db.execute(query, [params])` - Consulta clássica, retorna um Array of Array
- `db.executeOne(query, [params])` - Retorna o primeiro Array da consulta ou null
- `db.sequentially(query, [params], function(row, index), function(err), isArray)` - Realiza uma consulta de forma sequencial


### DirectDatabase

- `db.query(query, [params])` - Consulta clássica, retorna um Array of Object
- `db.queryOne(query, [params])` - Retorna o primeiro objeto da consulta ou null
- `db.execute(query, [params])` - Consulta clássica, retorna um Array of Array
- `db.executeOne(query, [params])` - Retorna o primeiro Array da consulta ou null
- `db.sequentially(query, [params], function(row, index), function(err), isArray)` - Realiza uma consulta de forma sequencial
- `db.detach()` - Finaliza a conexao direta com o banco de dados
- `db.transaction()` - Inicia uma transação com o banco de dados


### Transaction

- `transaction.query(query, [params])` - Consulta clássica, retorna um Array of Object
- `transaction.queryOne(query, [params])` - Retorna o primeiro objeto da consulta ou null
- `transaction.execute(query, [params])` - Consulta clássica, retorna um Array of Array
- `transaction.executeOne(query, [params])` - Retorna o primeiro Array da consulta ou null
- `transaction.sequentially(query, [params], function(row, index), function(err))` - Realiza uma consulta de forma sequencial


### DirectTransaction

- `transaction.query(query, [params])` - Consulta clássica, retorna um Array of Object
- `transaction.queryOne(query, [params])` - Retorna o primeiro objeto da consulta ou null
- `transaction.execute(query, [params])` - Consulta clássica, retorna um Array of Array
- `transaction.executeOne(query, [params])` - Retorna o primeiro Array da consulta ou null
- `transaction.sequentially(query, [params], function(row, index), function(err), isArray)` - Realiza uma consulta de forma sequencial
- `transaction.commit()` - Confirma as alterações realizadas na transação
- `transaction.rollback()` - Reverte as alterações realizadas na transação


### Exemplos:


### Conexão direta(ASYNCHRONOUS)
```js
router.post('/estabelecimento', (req, res, next) => {
    req.firebird.attachDataBase({
        host: '127.0.0.1',
        port: 3050,
        user: 'SYSDBA',
        password: 'masterkey',
        database: 'C:\\Limber\\DATA\\CDE_WIN.FDB',
        lowercase_keys: false,
        encoding: 'latin1'
    }, (db) => {
        db.transaction((err, transaction) => {
            if (err) {
                db.detach();
                next(err);
            } else {
                transaction.execute('INSERT INTO CAD_ESTABELECIMENTOS (EMPRESA, CODIGO, NOME) VALUES (?,?,?)', [req.body.empresa, req.body.codigo, req.body.nome],
                    (err, result) => {
                        if (err) {
                            transaction.rollback();
                            db.detach();
                            next(err);
                        } else {
                            transaction.query('SELECT E.EMPRESA, E.CODIGO, E.NOME FROM CAD_ESTABELECIMENTOS E WHERE E.CODIGO = ?', [req.query.codigo],
                                (err, result) => {
                                    if (err) {
                                        transaction.rollback();
                                        db.detach();
                                        next(err);
                                    } else {
                                        transaction.commit(err => {
                                            if (err) {
                                                transaction.rollback();
                                                db.detach();
                                                next(err);
                                            } else {
                                                db.detach();
                                                res.status(200).json(result);
                                            }
                                        });
                                    }
                                });
                        }
                    });
            }
        });
    });
});
```

### Conexão direta(SYNCHRONOUS)
```js
router.post('/estabelecimento', async (req, res, next) => {
    try {
        let db = await req.firebird.attachDataBase({
            host: '127.0.0.1',
            port: 3050,
            user: 'SYSDBA',
            password: 'masterkey',
            database: 'C:\\Limber\\DATA\\CDE_WIN.FDB',
            lowercase_keys: false,
            encoding: 'latin1'
        });

        let transaction = await db.transaction();
        try {
            await transaction.execute('INSERT INTO CAD_ESTABELECIMENTOS (EMPRESA, CODIGO, NOME) VALUES (?,?,?)', [req.body.empresa, req.body.codigo, req.body.nome]);

            let result = await transaction.query('SELECT E.EMPRESA, E.CODIGO, E.NOME FROM CAD_ESTABELECIMENTOS E WHERE E.CODIGO = ?', [req.query.codigo]);

            await transaction.commit();

            res.status(200).json(result);
        } catch (e) {
            await transaction.rollback();
            next(err);
        }
        await db.detach();
    } catch (err) {
        next(err);
    }
});

```


### Leitura (ASYNCHRONOUS)
```js
router.get('/estabelecimento', (req, res, next) => {
    req.firebird.openDataBaseRead((db) => {
        db.query('SELECT E.EMPRESA, E.CODIGO, E.NOME FROM CAD_ESTABELECIMENTOS E WHERE E.CODIGO = ?',
            [req.query.codigo], (err, result) => {
                if (err) {
                    next(err);
                } else {
                    res.status(200).json(result);
                }
            });
    });
});

```

### Leitura (SYNCHRONOUS)
```js
router.get('/estabelecimento', async (req, res, next) => {
    try {
        let db = await req.firebird.openDataBaseRead();
        let result = await db.query('SELECT E.EMPRESA, E.CODIGO, E.NOME FROM CAD_ESTABELECIMENTOS E WHERE E.CODIGO = ?', [req.query.codigo]);
        res.status(200).json(result);
    } catch (err) {
        next(err);
    }
});

```

### Gravação (ASYNCHRONOUS)
```js
router.post('/prevenda', (req, res, next) => {

    req.firebird.openDataBaseWrite((transaction) => {

        let EMPRESA = req.body.EMPRESA,
            CODIGO = req.body.CODIGO,
            ESTABELEC = req.body.ESTABELEC,
            TABPRECO = req.body.TABPRECO,
            DATA = req.body.DATA ,
            HORA = req.body.HORA,
            TOTAL = req.body.TOTAL;

            transaction.query("INSERT INTO PAF_PREVENDA (EMPRESA, CODIGO, ESTABELEC, TABPRECO, DATA, HORA, TOTAL, ID_TRANSACAO) " +
                "VALUES (?, ?, ?, ?, ?, ?, ?, GEN_ID(GEN_TRANSACOES0, 1)) RETURNING ID_TRANSACAO", 
                [EMPRESA, CODIGO, ESTABELEC, TABPRECO, DATA, HORA, TOTAL, TOTAL], (err, result) => {
                if (err) {
                    next(err);
                } else {
                    res.status(200).json(result);
                }
            });

    });

});

```

### Gravação (SYNCHRONOUS)
```js
router.post('/prevenda', async (req, res, next) => {
    try {
        let EMPRESA = req.body.EMPRESA,
            CODIGO = req.body.CODIGO,
            ESTABELEC = req.body.ESTABELEC,
            TABPRECO = req.body.TABPRECO,
            DATA = req.body.DATA ,
            HORA = req.body.HORA,
            TOTAL = req.body.TOTAL;
        
        let transaction = await req.firebird.openDataBaseWrite();
        let result = await transaction.query("INSERT INTO PAF_PREVENDA (EMPRESA, CODIGO, ESTABELEC, TABPRECO, DATA, HORA, TOTAL, ID_TRANSACAO) " +
            "VALUES (?, ?, ?, ?, ?, ?, ?, GEN_ID(GEN_TRANSACOES0, 1)) RETURNING ID_TRANSACAO",
            [EMPRESA, CODIGO, ESTABELEC, TABPRECO, DATA, HORA, TOTAL, TOTAL]);
        res.status(200).json(result);
    } catch (err) {
        next(err);
    }
});

```

### STREAMING A BIG DATA (ASYNCHRONOUS)

```js
router.get('/big', (req, res, next) => {
    req.firebird.openDataBaseRead((db) => {
        db.sequentially('SELECT * FROM BIGTABLE', function (row, index) {
            stream.write(JSON.stringify(row));
        }, (err) => {
           if (err){
               next(err);
           }else {
               res.status(200).send(stream);
           }
        });
    });
});

```

### STREAMING A BIG DATA (SYNCHRONOUS)

```js
router.get('/big', async (req, res, next) => {
    try {
        let db = await req.firebird.openDataBaseRead();
        await db.sequentially('SELECT * FROM BIGTABLE', (row, index) => stream.write(JSON.stringify(row)));
        res.status(200).json(stream);
    } catch (err) {
        next(err);
    }
});

```

### BLOB (stream)

```js
router.post('/user', (req, res, next) => {

    req.firebird.openDataBaseWrite((transaction) => {
        
        transaction.query('INSERT INTO USERS (ID, ALIAS, FILE) VALUES(?, ?, ?)', 
            [1, 'Peter', fs.createReadStream('/users/image.jpg')], (err, result) => {
            if (err) {
                next(err);
            } else {
                res.status(200).json(result);
            }
        });

    });

});

```

### BLOB (buffer)

```js
router.post('/user', (req, res, next) => {

    req.firebird.openDataBaseWrite((transaction) => {
        
        transaction.query('INSERT INTO USERS (ID, ALIAS, FILE) VALUES(?, ?, ?)', 
            [1, 'Peter', fs.readFileSync('/users/image.jpg')], (err, result) => {
            if (err) {
                next(err);
            } else {
                res.status(200).json(result);
            }
        });

    });

});
```

### READING BLOBS (ASYNCHRONOUS)

```js
router.get('/logo', (req, res, next) => {
    req.firebird.openDataBaseRead((db) => {
        db.query('SELECT E.LOGO FROM CAD_ESTABELECIMENTOS E WHERE E.EMPRESA = ? AND E.CODIGO = ?',
            [req.query.empresa, req.query.codigo], (err, result) => {
                if (err) {
                    next(err);
                } else if (result && result.length > 0 && result[0].LOGO) {
                     res.set({'Content-Type': 'image/png'});
                     res.status(200).send(result[0].LOGO);
                } else {
                    res.status(204).send('');
                }
            });
    });
});
```


## Desenvolvedor
- Limber Software e Consultoria LTDA
