Skip to content

thespamer/sqlbridge

Repository files navigation

SQLBridge 🌉

A biblioteca Python mais simples e transparente para abstração SQL multi-banco de dados.

PyPI version Python Versions Tests Coverage License: MIT Code style: black

🎯 Por que SQLBridge?

Diferente de ORMs pesados como SQLAlchemy, SQLBridge permite que você escreva SQL padrão simples e ele traduz automaticamente para qualquer banco de dados suportado.

Vantagens

  • SQL Nativo: Escreva SQL padrão, sem aprender nova sintaxe
  • Detecção Automática: Detecta o dialeto automaticamente pela conexão
  • Transparente: Funciona com qualquer driver DB-API 2.0
  • Leve: Sem overhead de ORM, zero dependências
  • Inteligente: Traduz tipos, funções e sintaxes automaticamente

Bancos Suportados

✅ MySQL / MariaDB
✅ PostgreSQL
✅ Oracle Database
✅ Microsoft SQL Server
✅ IBM DB2
✅ IBM Informix
✅ SQLite

Funcionalidades por Banco de Dados

Feature MySQL PostgreSQL Oracle SQL Server DB2 Informix SQLite
AUTO_INCREMENT ✅ SERIAL ✅ IDENTITY ✅ IDENTITY ✅ IDENTITY ✅ SERIAL ✅ AUTOINCREMENT
BOOLEAN ✅ TINYINT(1) ✅ Nativo ✅ NUMBER(1) ✅ BIT ✅ SMALLINT ✅ Nativo ✅ INTEGER
LIMIT/OFFSET ✅ Nativo ✅ Nativo ✅ FETCH ✅ FETCH ✅ FETCH ✅ SKIP/FIRST ✅ Nativo
DATE_ADD ✅ Nativo ✅ + INTERVAL ✅ + INTERVAL ✅ DATEADD ✅ + DAYS ✅ + INTERVAL ✅ datetime()
CONCAT ✅ CONCAT() ✅ || ✅ || ✅ + ✅ || ✅ || ✅ ||
CTEs ✅ 8.0+ ✅ 8.4+ ✅ 9i+ ✅ 2005+ ✅ 9.5+ ✅ 3.8.3+
Window Functions ✅ 8.0+ ✅ 8.4+ ✅ 8.1.6+ ✅ 2005+ ✅ 9.5+ ✅ 3.25.0+

🚀 Instalação

pip install sqlbridge

📖 Uso Básico

from sqlbridge import SQLBridge
import psycopg2

# 1. Você cria a conexão com o banco que escolher (PostgreSQL neste exemplo)
conn = psycopg2.connect("postgresql://localhost/mydb")

# 2. SQLBridge detecta automaticamente que é PostgreSQL
bridge = SQLBridge(conn)  # Detecta: "postgresql"

# 3. Escreva SQL padrão - o mesmo código funciona em qualquer banco!
sql = """
    CREATE TABLE users (
        id INTEGER AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(100) NOT NULL,
        email VARCHAR(255) UNIQUE,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    )
"""

# 4. SQLBridge traduz automaticamente para o dialeto PostgreSQL
bridge.execute(sql)

# SQL traduzido executado:
# CREATE TABLE users (
#     id SERIAL PRIMARY KEY,              -- AUTO_INCREMENT → SERIAL
#     name VARCHAR(100) NOT NULL,
#     email VARCHAR(255) UNIQUE,
#     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP  -- DATETIME → TIMESTAMP
# )

Como Funciona?

  1. Você escolhe o banco e cria a conexão (MySQL, PostgreSQL, etc.)
  2. SQLBridge detecta automaticamente o dialeto pela conexão
  3. Você escreve SQL padrão - sempre o mesmo código
  4. SQLBridge traduz para o dialeto específico do banco conectado

🎨 Exemplo Visual: Mesma Query, Bancos Diferentes

Seu código (sempre o mesmo):

sql = """
    CREATE TABLE users (
        id INTEGER AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(100),
        is_active BOOLEAN DEFAULT TRUE
    )
"""

Tradução automática para cada banco:

┌─────────────────────────────────────────────────────────────────┐
│ 🐬 MySQL                                                        │
├─────────────────────────────────────────────────────────────────┤
│ CREATE TABLE users (                                            │
│     id INTEGER AUTO_INCREMENT PRIMARY KEY,                      │
│     name VARCHAR(100),                                          │
│     is_active TINYINT(1) DEFAULT 1                              │
│ )                                                               │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 🐘 PostgreSQL                                                   │
├─────────────────────────────────────────────────────────────────┤
│ CREATE TABLE users (                                            │
│     id SERIAL PRIMARY KEY,                                      │
│     name VARCHAR(100),                                          │
│     is_active BOOLEAN DEFAULT TRUE                              │
│ )                                                               │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 🔶 Oracle                                                       │
├─────────────────────────────────────────────────────────────────┤
│ CREATE TABLE users (                                            │
│     id NUMBER GENERATED AS IDENTITY PRIMARY KEY,                │
│     name VARCHAR(100),                                          │
│     is_active NUMBER(1) DEFAULT 1                               │
│ )                                                               │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 🪟 SQL Server                                                   │
├─────────────────────────────────────────────────────────────────┤
│ CREATE TABLE users (                                            │
│     id INTEGER IDENTITY(1,1) PRIMARY KEY,                       │
│     name VARCHAR(100),                                          │
│     is_active BIT DEFAULT 1                                     │
│ )                                                               │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 💾 SQLite                                                       │
├─────────────────────────────────────────────────────────────────┤
│ CREATE TABLE users (                                            │
│     id INTEGER AUTOINCREMENT PRIMARY KEY,                       │
│     name VARCHAR(100),                                          │
│     is_active INTEGER DEFAULT 1                                 │
│ )                                                               │
└─────────────────────────────────────────────────────────────────┘

🔄 Outro Exemplo: Paginação

Seu código:

sql = "SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20"

Tradução automática:

┌─────────────────────────────────────────────────────────────────┐
│ 🐬 MySQL / 🐘 PostgreSQL / 💾 SQLite                            │
├─────────────────────────────────────────────────────────────────┤
│ SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20             │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 🔶 Oracle / 🪟 SQL Server / 🔷 DB2                              │
├─────────────────────────────────────────────────────────────────┤
│ SELECT * FROM users ORDER BY id                                │
│ OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY                         │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 🔵 Informix                                                     │
├─────────────────────────────────────────────────────────────────┤
│ SELECT SKIP 20 FIRST 10 * FROM users ORDER BY id               │
└─────────────────────────────────────────────────────────────────┘

📊 Exemplo: Concatenação de Strings

Seu código:

sql = "SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users"

Tradução automática:

┌─────────────────────────────────────────────────────────────────┐
│ 🐬 MySQL                                                        │
├─────────────────────────────────────────────────────────────────┤
│ SELECT CONCAT(first_name, ' ', last_name) AS full_name         │
│ FROM users                                                      │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 🐘 PostgreSQL / 🔶 Oracle / 🔷 DB2 / 🔵 Informix / 💾 SQLite   │
├─────────────────────────────────────────────────────────────────┤
│ SELECT first_name || ' ' || last_name AS full_name             │
│ FROM users                                                      │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 🪟 SQL Server                                                   │
├─────────────────────────────────────────────────────────────────┤
│ SELECT first_name + ' ' + last_name AS full_name               │
│ FROM users                                                      │
└─────────────────────────────────────────────────────────────────┘

💡 A mágica: Você escreve uma vez, SQLBridge traduz para todos os bancos!

🏗️ Query Builder Fluente

SQLBridge inclui um Query Builder poderoso para construir queries programaticamente:

from sqlbridge import SQLBridge, QueryBuilder, table
import sqlite3

conn = sqlite3.connect('mydb.db')
bridge = SQLBridge(conn)

# SELECT com Query Builder
query = (QueryBuilder('users')
    .select('id', 'name', 'email')
    .where('age', '>', 18)
    .where('city', '=', 'São Paulo')
    .order_by('name', 'ASC')
    .limit(10))

# Executar query
results = bridge.execute_builder(query)

# Ou construir SQL para ver
print(query.build())  # SELECT id, name, email FROM users WHERE age > ? AND city = ? ORDER BY name ASC LIMIT 10
print(query.get_params())  # [18, 'São Paulo']

Exemplos do Query Builder

# INSERT
query = (QueryBuilder('users')
    .insert({
        'name': 'Alice',
        'email': 'alice@example.com',
        'age': 30
    }))
bridge.execute_builder(query)

# UPDATE
query = (QueryBuilder('users')
    .update({'age': 31})
    .where('name', '=', 'Alice'))
bridge.execute_builder(query)

# DELETE
query = (QueryBuilder('users')
    .delete()
    .where('is_active', '=', 0))
bridge.execute_builder(query)

# JOIN
query = (QueryBuilder('posts')
    .select('posts.title', 'users.name')
    .inner_join('users', 'posts.user_id = users.id')
    .where('posts.views', '>', 100)
    .order_by('posts.views', 'DESC'))
results = bridge.execute_builder(query)

# GROUP BY e HAVING
query = (QueryBuilder('orders')
    .select('customer_id', 'COUNT(*) as order_count', 'SUM(total) as total_spent')
    .group_by('customer_id')
    .having('COUNT(*) > ?', 5)
    .order_by('total_spent', 'DESC'))
results = bridge.execute_builder(query)

# Helper function
query = (table('users')
    .select('name', 'email')
    .where('city', '=', 'Rio de Janeiro')
    .limit(5))
results = bridge.execute_builder(query)

Vantagens do Query Builder:

  • Type-safe: Menos erros de sintaxe SQL
  • Fluente: Encadeamento de métodos intuitivo
  • Reutilizável: Construa queries dinamicamente
  • Tradução automática: Funciona com todos os bancos
  • Prepared statements: Proteção contra SQL injection

🔥 Exemplos Avançados

Tradução Automática de Tipos

# SQL Padrão
sql = """
    CREATE TABLE products (
        id INTEGER AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(100),
        price DECIMAL(10,2),
        description TEXT,
        is_active BOOLEAN DEFAULT TRUE,
        created_at DATETIME
    )
"""

# MySQL: AUTO_INCREMENT, TINYINT(1)
# PostgreSQL: SERIAL, BOOLEAN, TIMESTAMP
# Oracle: NUMBER, CLOB, NUMBER(1), TIMESTAMP
# SQL Server: IDENTITY, BIT, DATETIME2

Funções de Data/Hora

# SQL Padrão
sql = "SELECT CURRENT_TIMESTAMP, DATE_ADD(created_at, INTERVAL 7 DAY) FROM orders"

# MySQL: CURRENT_TIMESTAMP, DATE_ADD(created_at, INTERVAL 7 DAY)
# PostgreSQL: CURRENT_TIMESTAMP, created_at + INTERVAL '7 days'
# Oracle: SYSTIMESTAMP, created_at + INTERVAL '7' DAY
# SQL Server: GETDATE(), DATEADD(day, 7, created_at)

LIMIT/OFFSET

# SQL Padrão
sql = "SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20"

# MySQL/PostgreSQL/SQLite: LIMIT 10 OFFSET 20
# SQL Server: OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
# Oracle: OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY

String Concatenation

# SQL Padrão
sql = "SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users"

# MySQL: CONCAT(first_name, ' ', last_name)
# PostgreSQL: first_name || ' ' || last_name
# SQL Server: first_name + ' ' + last_name
# Oracle: first_name || ' ' || last_name

CTEs (Common Table Expressions)

# SQL Padrão - Suportado nativamente em todos os bancos modernos
sql = """
    WITH dept_avg AS (
        SELECT department, AVG(salary) as avg_salary
        FROM employees
        GROUP BY department
    )
    SELECT e.name, e.salary, d.avg_salary
    FROM employees e
    JOIN dept_avg d ON e.department = d.department
"""

bridge.execute(sql)
# Funciona em: MySQL 8.0+, PostgreSQL 8.4+, Oracle 9i+, SQL Server 2005+, DB2, SQLite 3.8.3+

Window Functions

# SQL Padrão - Suportado nativamente
sql = """
    SELECT 
        name,
        salary,
        department,
        ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rank,
        AVG(salary) OVER (PARTITION BY department) as dept_avg
    FROM employees
"""

bridge.execute(sql)
# Funciona em: MySQL 8.0+, PostgreSQL 8.4+, Oracle 8.1.6+, SQL Server 2005+, SQLite 3.25.0+

🛠️ API Completa

SQLBridge

bridge = SQLBridge(connection, dialect='auto')

Parâmetros:

  • connection: Conexão DB-API 2.0
  • dialect: 'auto', 'mysql', 'postgresql', 'oracle', 'sqlserver', 'db2', 'informix', 'sqlite'

Métodos:

# Executar SQL traduzido
bridge.execute(sql, params=None)

# Obter SQL traduzido sem executar
translated_sql = bridge.translate(sql)

# Executar query e retornar resultados
results = bridge.query(sql, params=None)

# Executar múltiplos statements
bridge.execute_many(sql_list)

🎨 Recursos Avançados

Modo Debug

bridge = SQLBridge(conn, debug=True)
bridge.execute(sql)
# Imprime: [SQLBridge] Original: SELECT ...
# Imprime: [SQLBridge] Translated: SELECT ...

Tradução Manual

from sqlbridge.dialects import MySQLDialect, PostgreSQLDialect

mysql_dialect = MySQLDialect()
pg_dialect = PostgreSQLDialect()

# Traduzir de MySQL para PostgreSQL
mysql_sql = "SELECT * FROM users LIMIT 10"
standard_sql = mysql_dialect.to_standard(mysql_sql)
pg_sql = pg_dialect.from_standard(standard_sql)

Detecção de Dialeto

from sqlbridge import detect_dialect

dialect = detect_dialect(connection)
print(f"Banco detectado: {dialect}")

🖥️ CLI - Interface de Linha de Comando

SQLBridge inclui um CLI poderoso para traduzir scripts SQL:

# Traduzir arquivo SQL
sqlbridge translate -i script.sql -o output.sql -t postgresql

# Traduzir e imprimir no terminal
sqlbridge translate -i script.sql -t mysql

# Traduzir do stdin
echo "SELECT * FROM users LIMIT 10" | sqlbridge translate -t oracle

# Listar dialetos suportados
sqlbridge list

# Ver exemplos
sqlbridge examples

Exemplos de Uso do CLI

# Converter script MySQL para PostgreSQL
sqlbridge translate -i mysql_schema.sql -o postgres_schema.sql -t postgresql

# Comparar traduções entre bancos
sqlbridge translate -i script.sql -t mysql > mysql.sql
sqlbridge translate -i script.sql -t postgresql > postgresql.sql
diff mysql.sql postgresql.sql

# Pipeline com outros comandos
cat migration.sql | sqlbridge translate -t sqlserver | ssh server "psql -f -"

🧪 Testes

# Instalar dependências de desenvolvimento
pip install -e ".[dev]"

# Rodar testes
pytest tests/

# Cobertura
pytest --cov=sqlbridge tests/

🆚 Comparação com Outras Bibliotecas

Tabela Comparativa

Feature SQLBridge SQLAlchemy Django ORM Peewee PyDAL Records
SQL Nativo ⚠️ Possível ⚠️ Limitado
Tradução Automática ⚠️ Via API
Zero Dependências
CLI ✅ Manage
ORM ✅ Completo ✅ Completo ✅ Leve
Curva de Aprendizado ⭐ Baixa ⭐⭐⭐⭐⭐ Muito Alta ⭐⭐⭐ Média ⭐⭐ Baixa ⭐⭐⭐ Média ⭐ Baixa
Migrations 🚧 Em dev ✅ Alembic ✅ Integrado ✅ Auto
CTEs ⚠️
Window Functions ⚠️
Tamanho ~3.5k LOC ~100k+ LOC ~50k+ LOC ~10k LOC ~15k LOC ~1k LOC
Multi-Banco ✅ 7 bancos
Standalone ❌ Requer Django

Quando Usar Cada Uma?

✅ Use SQLBridge quando:

  • Você prefere escrever SQL nativo
  • Precisa suportar múltiplos bancos sem reescrever código
  • Quer tradução automática de SQL
  • Precisa migrar entre bancos de dados
  • Quer uma solução leve (zero dependências)
  • Precisa de CLI para traduzir scripts
  • Valoriza simplicidade e controle total

✅ Use SQLAlchemy quando:

  • Precisa de um ORM completo e robusto
  • Projeto grande e complexo
  • Precisa de migrations avançadas (Alembic)
  • Quer mapeamento objeto-relacional
  • Já conhece a biblioteca

✅ Use Django ORM quando:

  • Está usando Django framework
  • Precisa de admin interface
  • Quer migrations integradas
  • Projeto web completo

✅ Use Peewee quando:

  • Quer um ORM simples e leve
  • Projeto pequeno/médio
  • Não quer a complexidade do SQLAlchemy

Exemplo Comparativo

Criar tabela em múltiplos bancos:

# SQLBridge - Mesmo código funciona em qualquer banco
from sqlbridge import SQLBridge

bridge = SQLBridge(connection)  # MySQL, PostgreSQL, Oracle, etc.
bridge.execute("""
    CREATE TABLE users (
        id INTEGER AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(100),
        is_active BOOLEAN DEFAULT TRUE
    )
""")
# Traduz automaticamente:
# MySQL: AUTO_INCREMENT, TINYINT(1)
# PostgreSQL: SERIAL, BOOLEAN
# Oracle: GENERATED AS IDENTITY, NUMBER(1)
# SQL Server: IDENTITY(1,1), BIT
# SQLAlchemy - Precisa definir classes
from sqlalchemy import Column, Integer, String, Boolean
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(100))
    is_active = Column(Boolean, default=True)

Base.metadata.create_all(engine)

Performance

Inserção de 10.000 registros (benchmark típico):

Biblioteca Tempo Overhead
SQLBridge ~2.5s Mínimo
SQLAlchemy Core ~2.3s Baixo
Peewee ~3.0s Baixo
SQLAlchemy ORM ~8.5s Alto
Django ORM ~9.0s Alto

SQLBridge oferece performance próxima ao SQL puro, sem overhead de ORM.

Filosofia

SQLBridge: "Escreva SQL padrão uma vez, execute em qualquer banco de dados"

SQLAlchemy: "Python classes para representar tabelas"

Django ORM: "ORM integrado ao framework"

SQLBridge complementa, não substitui outras bibliotecas. É uma ferramenta especializada em tradução SQL transparente.

📖 Comparação detalhada: Veja COMPARISON.md para análise completa.

❓ FAQ (Perguntas Frequentes)

P: Preciso saber qual banco estou usando?

R: Sim! Você precisa criar a conexão com o banco específico (MySQL, PostgreSQL, etc.). O SQLBridge detecta automaticamente o dialeto a partir dessa conexão.

# Você escolhe e conecta ao banco
import psycopg2
conn = psycopg2.connect("postgresql://localhost/mydb")

# SQLBridge detecta automaticamente que é PostgreSQL
bridge = SQLBridge(conn)

P: SQLBridge substitui o driver do banco?

R: Não! SQLBridge trabalha em cima dos drivers nativos (psycopg2, mysql-connector, etc.). Você ainda precisa:

  1. Instalar o driver do banco (pip install psycopg2)
  2. Criar a conexão com o driver
  3. Passar a conexão para o SQLBridge

P: Qual a vantagem então?

R: O mesmo código SQL funciona em qualquer banco:

# Este SQL funciona em MySQL, PostgreSQL, Oracle, SQL Server, etc.
sql = "CREATE TABLE users (id INTEGER AUTO_INCREMENT PRIMARY KEY)"

# MySQL: id INTEGER AUTO_INCREMENT PRIMARY KEY
# PostgreSQL: id SERIAL PRIMARY KEY
# Oracle: id NUMBER GENERATED AS IDENTITY PRIMARY KEY
# SQL Server: id INTEGER IDENTITY(1,1) PRIMARY KEY

P: Preciso mudar meu código para trocar de banco?

R: Não! Apenas mude a conexão:

# Desenvolvimento: SQLite
conn = sqlite3.connect('dev.db')

# Produção: PostgreSQL
conn = psycopg2.connect('postgresql://...')

# O resto do código permanece IDÊNTICO!
bridge = SQLBridge(conn)
bridge.execute(sql)  # Mesmo SQL, tradução automática

P: SQLBridge funciona com ORMs?

R: Sim! SQLBridge é complementar. Use para:

  • Migrations entre bancos
  • Scripts SQL diretos
  • Queries complexas
  • Quando você prefere SQL nativo

P: Posso forçar um dialeto específico?

R: Sim!

# Detecção automática (recomendado)
bridge = SQLBridge(conn)

# Forçar dialeto específico
bridge = SQLBridge(conn, dialect='postgresql')

P: Quais versões de cada banco são suportadas?

R: Versões modernas de cada banco:

  • MySQL: 5.7+ (CTEs requerem 8.0+)
  • PostgreSQL: 9.0+ (CTEs desde 8.4+)
  • Oracle: 11g+ (CTEs desde 9i+)
  • SQL Server: 2012+ (CTEs desde 2005+)
  • DB2: 9.5+
  • Informix: 11.50+
  • SQLite: 3.8+ (Window Functions desde 3.25+)

📋 Roadmap

  • Suporte básico para 7 bancos de dados
  • Tradução de tipos de dados
  • Tradução de funções comuns
  • Suporte a CTEs (Common Table Expressions)
  • Suporte a Window Functions
  • CLI para tradução de scripts SQL
  • Tradução de stored procedures
  • Plugin para IDEs
  • Query builder fluente
  • Schema migrations automáticas

🤝 Contribuindo

Contribuições são bem-vindas! Por favor:

  1. Fork o projeto
  2. Crie uma branch para sua feature (git checkout -b feature/AmazingFeature)
  3. Commit suas mudanças (git commit -m 'Add some AmazingFeature')
  4. Push para a branch (git push origin feature/AmazingFeature)
  5. Abra um Pull Request

📄 Licença

MIT License - veja LICENSE para detalhes.

👨‍💻 Autor

Criado com ❤️ para simplificar o desenvolvimento multi-banco de dados.

🙏 Agradecimentos

Inspirado por SQLAlchemy, mas focado em simplicidade e transparência.

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages