npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

firebird-orm

v1.0.0

Published

Um ORM elegante e tipado para Firebird

Readme

firebird-orm

ORM elegante, tipado e com decorators para Firebird 2.5 / 3.0 / 4.0 / 5.0, escrito em TypeScript e construído sobre o driver node-firebird.

CI npm version License: MIT TypeScript

Um ORM pequeno, explícito e sem mágica. Mapeia classes TypeScript para tabelas Firebird usando decorators, oferece um Repository genérico com CRUD completo, suporte a BLOB, stored procedures, query builder fluente e uma CLI de migrations. Foi pensado para desenvolvedores (e agentes de IA) que precisam lidar com os quirks reais do Firebird sem trocar a simplicidade do TypeScript.


Sumário


Por que firebird-orm?

  • Tipado de verdade. Decorators geram metadados em tempo de compilação; tudo é Repository<T>, FindOptions<T> etc.
  • Nada de DSL própria vazando para o SQL. Você lê o banco como uma classe TS. Tabela/coluna vão em MAIÚSCULO por convenção.
  • Honesto com o Firebird. Respeita FIRST/SKIP, sequences, RETURNING, SMALLINT para booleanos, BLOB SUB_TYPE, EXECUTE PROCEDURE vs SELECT * FROM procedure.
  • CLI de migrations inclusa. migration:generate, migration:run, migration:revert — sem precisar montar TypeORM/Prisma/MikroORM para um sistema legado.
  • Erros acionáveis. Mensagens dizem o que está faltando e como corrigir (NoPrimaryKeyError, EntityNotFoundError, etc.).

Instalação

npm install firebird-orm

O pacote depende de reflect-metadata e node-firebird (incluídos como dependências).

No tsconfig.json do seu projeto:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "strict": true
    // ...
  }
}

E importe o polyfill uma única vez, no entrypoint:

import 'reflect-metadata';

Sem fbclient.dll? O node-firebird 1.x é JavaScript puro; em servidores Linux a fbclient do próprio Firebird já atende. Em Windows, aponte LD_LIBRARY_PATH/PATH para a pasta do cliente se o seu Firebird exigir.


Início rápido

import 'reflect-metadata';
import {
  createConnection,
  Entity,
  PrimaryGeneratedColumn,
  Column,
  Repository,
} from 'firebird-orm';

// 1. Defina a entidade
@Entity('USUARIOS')
class Usuario {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column()
  nome!: string;

  @Column({ name: 'EMAIL', type: 'string' })
  email!: string;

  @Column({ name: 'ATIVO', type: 'boolean' })
  ativo!: boolean;
}

// 2. Abra a conexão (pool interno)
const connection = await createConnection({
  host: 'localhost',
  port: 3050,
  database: '/var/lib/firebird/data/sistema.fdb', // ou 'C:\\dados\\sistema.fdb' no Windows
  user: 'SYSDBA',
  password: 'masterkey',
  poolSize: 5,
});

// 3. Use o repositório
const usuarios: Repository<Usuario> = await connection.getRepository(Usuario);

// Criar
const novo = await usuarios.save({ nome: 'João Silva', email: '[email protected]', ativo: true });
console.log(novo.id); // ID veio da sequence automaticamente

// Buscar
const todos = await usuarios.find({ orderBy: { nome: 'ASC' }, take: 10 });
const um = await usuarios.findOne(novo.id);
await usuarios.findOneOrFail(9999); // lança EntityNotFoundError

// Atualizar / deletar
await usuarios.update(novo.id, { ativo: false });
await usuarios.delete(novo.id);

// Contar
const totalAtivos = await usuarios.count({ ativo: true });

// Fechar (libera o pool)
await connection.close();

Recursos em destaque

CRUD com Repository

Repository<T> expõe find, findOne, findOneOrFail, save (upsert por PK), update, delete e count. Sem WHERE arbitrário em find() — para queries dinâmicas, use o FluentQueryBuilder.

const usuarios = await connection.getRepository(Usuario);

const ativos = await usuarios.find({
  where: { ativo: true },
  orderBy: { nome: 'ASC' },
  take: 10,
  skip: 0, // vira FIRST 10 SKIP 0 no SQL
  select: ['id', 'nome', 'email'],
});

find() ordena pela chave primária por padrão, então paginação é sempre determinística (sem ORDER BY em queries FIRST/SKIP no Firebird, a ordem é física).

Transações

connection.transaction(...) encapsula READ_COMMITTED + commit automático ou rollback em caso de erro. Use-a com queries raw ou repositórios.

const total = await connection.transaction(async (trx) => {
  await connection.query('UPDATE ESTOQUE SET QTD = QTD - ? WHERE PRODUTO_ID = ?', [3, produtoId], trx);
  await connection.query('INSERT INTO MOVIMENTACOES (...) VALUES (...)', [...], trx);
  return 'ok';
});

Dentro de trx as queries devem usar o objeto de transação — não chamar connection.query direto (ele pegaria outra conexão do pool).

Stored Procedures

import { ProcedureBuilder } from 'firebird-orm';

// Executable (ação / retorno único)
const [{ TOTAL }] = await connection.callProcedure<{ TOTAL: number }>(
  'SP_CALCULA_FRETE',
  [peso, cep],
);

// Selectable (retorna várias linhas)
const relatorio = await connection.callProcedure<{ LINHA: string }>(
  'SP_RELATORIO_VENDAS',
  [dataIni, dataFim],
  'selectable',
);

ProcedureBuilder.build(...) também monta o SQL direto se quiser baixar para raw:

const { sql, params } = ProcedureBuilder.build('SP_SOMA', [10, 20], 'executable');
// sql: "EXECUTE PROCEDURE SP_SOMA(?, ?)"

Query Builder fluente

Para queries complexas, connection.createQueryBuilder(Entidade) retorna um builder encadeável:

const ativos = await connection
  .createQueryBuilder(Usuario)
  .where('ATIVO = ?', [1])
  .andWhere('NOME LIKE ?', ['João%'])
  .orderBy('NOME', 'ASC')
  .take(10)
  .skip(0)
  .getMany();

const um = await fqb.where('ID = ?', [42]).getOne();
const total = await fqb.where('ATIVO = ?', [1]).getCount();

BLOB (binário e texto)

Campos BLOB chegam via node-firebird como função de stream. O Repository resolve isso automaticamente no find/findOne. Para usos de baixo nível:

import { resolveBlob } from 'firebird-orm';

const buffer = await resolveBlob(row.CAMPO_BLOB);

CLI de Migrations

O pacote expõe o binário firebird-orm. Após npm run build:

# 1. Crie o arquivo firebird-orm.config.(js|json) na raiz do projeto
cat > firebird-orm.config.js <<'EOF'
module.exports = {
  host: 'localhost',
  port: 3050,
  database: './data/sistema.fdb',
  user: 'SYSDBA',
  password: 'masterkey',
  migrationsDir: './src/migrations',
  migrationsTable: 'MIGRATIONS',
};
EOF

# 2. Gere / rode / reverta
npx firebird-orm migration:generate -n CreateUsuarios
npx firebird-orm migration:run
npx firebird-orm migration:revert

Cada migration é uma classe TypeScript que implementa a interface Migration:

import { Migration, FirebirdConnection } from 'firebird-orm';

export class CreateUsuarios1625097600000 implements Migration {
  name = 'CreateUsuarios1625097600000';

  async up(connection: FirebirdConnection): Promise<void> {
    await connection.query(`
      CREATE TABLE USUARIOS (
        ID INTEGER NOT NULL PRIMARY KEY,
        NOME VARCHAR(100) NOT NULL,
        EMAIL VARCHAR(150),
        ATIVO SMALLINT DEFAULT 1
      )
    `);
    await connection.query('CREATE SEQUENCE GEN_USUARIOS_ID');
  }

  async down(connection: FirebirdConnection): Promise<void> {
    await connection.query('DROP TABLE USUARIOS');
    await connection.query('DROP SEQUENCE GEN_USUARIOS_ID');
  }
}

Renomear tabelas? O Firebird não suporta RENAME TABLE. A estratégia de migration para rename é: criar a nova, copiar dados, dropar a antiga.


Quirks do Firebird

O ORM aplica essas convenções automaticamente — fique atento se for escrever SQL na mão:

| Tópico | MySQL / PostgreSQL | Firebird | |---|---|---| | Paginação | LIMIT 10 OFFSET 20 | SELECT FIRST 10 SKIP 20 * FROM T | | IDs automáticos | AUTO_INCREMENT / SERIAL | SEQUENCE + NEXT VALUE FOR GEN_T_ID | | Insert com ID | INSERT ... RETURNING id | mesmo, ou NEXT VALUE FOR separado | | Booleanos | BOOLEAN | SMALLINT (0/1) — use @Column({ type: 'boolean' }) para coerção | | Strings vazias | '' != NULL | '' é NULL no Firebird 2.5 | | Case de nomes | conforme aspas | sem aspas → MAIÚSCULO (o ORM já normaliza) | | Texto longo | TEXT | BLOB SUB_TYPE TEXT | | Datas | DATETIME, TIMESTAMP | DATE, TIME, TIMESTAMP | | Transação | opcional | obrigatória para escrita |

Se preferir ler em formato llms.txt (para agentes de IA), veja llms.txt.


Compatibilidade

| Componente | Versão | |---|---| | Node.js | 18+ (testado em 20.x) | | TypeScript | 4.5+ (peerDependencies) — testado em 5.x | | Firebird | 2.5, 3.0, 4.0, 5.0 | | Driver | node-firebird 1.1.x |

Para Firebird 5.0 com usuários legados (Legacy_Auth), informe a opção na conexão:

createConnection({ /* ... */, pluginName: 'Legacy_Auth' });

Configuração de testes / docker

O repositório traz specs unitários (Jest) e specs de integração contra um Firebird real (via docker-compose.yml).

# Unitários (sem Firebird)
npm test -- --testPathIgnorePatterns=integration

# Integração (precisa do container)
docker compose up -d
npm test -- src/__tests__/integration

Os 5 arquivos em src/__tests__/integration/ lêem FB_HOST/FB_PORT/FB_DATABASE/FB_USER/FB_PASSWORD/FB_PLUGIN_NAME do ambiente, com defaults compatíveis com o docker-compose.yml.

CI no GitHub Actions roda as duas suítes em todo PR (.github/workflows/ci.yml).


Versionamento e changelog

A versão atual é 1.0.0 — API estável. Sem breaking changes planejadas até a próxima minor.


Contribuição e licença

PRs são bem-vindos — abra a issue primeiro descrevendo o que vai mudar.