Metadata-Version: 2.4
Name: dbbridgekit
Version: 0.4.0
Summary: Database migration toolkit built on a canonical IR: real schema and data migration across 10 SQL dialects (with checksum validation), a Compatibility Mode shim for zero-downtime cutover, and safe SQL/NoSQL transition blueprints — never a silent guess.
Author-email: Otavio R Santana <tvostrodrigues8@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/tvost2/dbbridgekit
Project-URL: Repository, https://github.com/tvost2/dbbridgekit
Project-URL: Issues, https://github.com/tvost2/dbbridgekit/issues
Project-URL: Documentation, https://github.com/tvost2/dbbridgekit/blob/main/docs/guide.md
Project-URL: Changelog, https://github.com/tvost2/dbbridgekit/blob/main/CHANGELOG.md
Keywords: sql,nosql,sqlite,postgresql,mysql,mongodb,migration,ir,database,ai
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: psycopg[binary]>=3.1
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Requires-Dist: moto[s3]>=5.0; extra == "dev"
Requires-Dist: fakeredis>=2.20; extra == "dev"
Provides-Extra: mongodb
Requires-Dist: pymongo>=4.6; extra == "mongodb"
Provides-Extra: mysql
Requires-Dist: pymysql>=1.1; extra == "mysql"
Provides-Extra: dbf
Requires-Dist: dbfread>=2.0; extra == "dbf"
Provides-Extra: duckdb
Requires-Dist: duckdb>=1.0; extra == "duckdb"
Provides-Extra: snowflake
Requires-Dist: snowflake-connector-python>=3.10; extra == "snowflake"
Provides-Extra: neo4j
Requires-Dist: neo4j>=5.0; extra == "neo4j"
Provides-Extra: opensearch
Requires-Dist: opensearch-py>=2.4; extra == "opensearch"
Provides-Extra: cassandra
Requires-Dist: cassandra-driver>=3.28; extra == "cassandra"
Provides-Extra: client
Requires-Dist: httpx>=0.27; extra == "client"
Provides-Extra: s3
Requires-Dist: boto3>=1.34; extra == "s3"
Provides-Extra: redis
Requires-Dist: redis>=5.0; extra == "redis"
Provides-Extra: ai-backend
Requires-Dist: openai>=1.0; extra == "ai-backend"
Provides-Extra: server
Requires-Dist: fastapi>=0.115; extra == "server"
Requires-Dist: uvicorn>=0.34; extra == "server"
Requires-Dist: bcrypt>=4.0; extra == "server"
Requires-Dist: pyjwt>=2.9; extra == "server"
Requires-Dist: python-multipart>=0.0.9; extra == "server"
Requires-Dist: httpx>=0.27; extra == "server"
Requires-Dist: email-validator>=2.0; extra == "server"
Requires-Dist: pyotp>=2.9; extra == "server"
Requires-Dist: fpdf2>=2.8; extra == "server"
Dynamic: license-file

# DBBridge

[![PyPI](https://img.shields.io/pypi/v/dbbridgekit)](https://pypi.org/project/dbbridgekit/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![Tests](https://img.shields.io/badge/tests-950%2B%20passing-brightgreen)]()

Plataforma genérica de conversão, análise e migração entre bancos de dados, baseada numa
**Intermediate Representation (IR)** canônica — não um conversor pareado por combinação de bancos.

```txt
Banco origem → Parser do dialeto origem → IR canônica → Renderer do dialeto destino → Banco destino
```

Qualquer par de dialetos suportados passa pelo mesmo pipeline — inclusive entre paradigmas
(SQL → documento, SQL → grafo, SQL → wide-column).

```bash
pip install dbbridgekit
dbbridge scan --from sqlite --to postgres ./meu-projeto     # o que quebra no destino?
dbbridge translate --from sqlite --to postgres schema.sql   # traduz o schema (preview, não escreve nada)
dbbridge execute-plan --from sqlite --to postgres schema.sql \
    --apply-schema --target-dsn "host=localhost dbname=app" \
    --source-dsn ./app.db --tables users leads              # aplica schema + migra dados + valida, tudo num comando
```

Guia rápido com todos os fluxos: [QUICK_START.md](QUICK_START.md). Prefere interface web com
IA e relatórios? Veja o [DBBridge Cloud](https://dbbridge.mytheria.com.br) — mesma engine,
zero infraestrutura.

## Status

| Dialeto | Parser | Renderer | Compatibility Mode (`connect()`) | Tradução de erro |
|---|---|---|---|---|
| SQLite | ✅ | ✅ | ✅ | ✅ |
| PostgreSQL | ✅ | ✅ | ✅ | ✅ |
| MySQL | ✅ | ✅ | ✅ (via `pymysql`, extra `[mysql]`) | ✅ |
| DuckDB | ✅ | ✅ | ✅ (arquivo `.duckdb` real) | ✅ |
| Snowflake | ✅ | ✅ | ✅ (conta real, extra `[snowflake]`) | ✅ |
| SQL Server | ✅ | ✅ | ✅ (placeholder `?`/pyodbc) | ✅ |
| Oracle / DB2 | ✅ | ✅ | integração em progresso | ✅ |
| MongoDB | blueprint + simulação | blueprint + simulação | simulação real via PyMongo | ✅ |
| Neo4j / Cassandra / OpenSearch | semântico | Cypher / CQL / mapping | execução real validada por checksum | ✅ |

`dbbridge.dialects.mysql` segue o mesmo contrato dos dialetos SQLite/PostgreSQL:
parseia/renderiza o subconjunto seguro de DDL comum e marca código procedural ou ambíguo como
`REVIEW_REQUIRED`, em vez de tentar uma tradução perigosa. Compatibility Mode com MySQL como
destino usa PyMySQL por baixo (`connect(source_dialect=..., target_dialect="mysql", dsn=...)`).

**Tradução de erro** (novo): além de traduzir a SINTAXE da query entre dialetos, o Compatibility
Mode agora também traduz a EXCEÇÃO nativa de cada driver (`sqlite3.IntegrityError`,
`psycopg.errors.UniqueViolation`, `pymysql.err.IntegrityError`, `pymongo.errors.DuplicateKeyError`,
...) pra uma hierarquia canônica (`dbbridge.errors`) — código que capture
`UniqueViolationError`/`ForeignKeyViolationError`/`DeadlockError`/etc. continua funcionando
IGUAL não importa qual banco está por trás do `connect()`. Ver [docs/guide.md](docs/guide.md#tradução-de-erros)
pro mapeamento completo por dialeto.

950+ testes, 86%+ de cobertura (`pytest --cov=dbbridge`). Os poucos pontos não cobertos são
código genuinamente inalcançável (stubs de método abstrato, guard `if __name__ == "__main__"`) ou
a fração de round-trip real dos executores NoSQL que só roda com Neo4j/Cassandra/OpenSearch
locais acessíveis — ver [docs/guide.md](docs/guide.md#cobertura-de-testes).

SQLite, PostgreSQL, MySQL e DuckDB são `fully_supported` (schema + dados + validação por checksum +
ida e volta ponta a ponta, provado pela suíte pública de testes). Snowflake e DBF são
`migration_supported` (migração real de schema/dados testada contra uma instância de verdade, mas
ainda sem a mesma prova de ponta a ponta que os quatro acima têm). MongoDB, Neo4j, Cassandra e
OpenSearch são `rewrite_supported` (execução real testada contra instâncias de verdade via
simulador/checksum, mas sem migração de schema/dados orquestrada, e sem `production_apply`, por
decisão deliberada de segurança). SQL Server, Oracle, DB2, Redis, ScyllaDB, Elasticsearch, BigQuery
e Redshift são `partial` (parser semântico real, mas sem validação contra servidor de verdade
nesta versão); CouchDB, Firestore, DynamoDB e JanusGraph também são `partial`, mas já com renderer
real e testado (índices Mango/partition+sort key/coleções e subcoleções/Gremlin) — falta só a
execução validada contra um servidor de verdade pra subir de nível. Ver
[docs/compatibility-matrix.md](docs/compatibility-matrix.md) pra matriz completa de suporte por
banco e [docs/guide.md](docs/guide.md#renderers-reais-pra-famílias-nosql-automationtargetpy-automationexecutionpy)
pros renderers reais de cada família NoSQL.

## Instalação

```bash
pip install -e .
# ou, pra rodar contra PostgreSQL de verdade:
pip install -e ".[dev]"
# para Compatibility Mode/migração contra MySQL de verdade:
pip install -e ".[mysql]"
# para simulação MongoDB contra serviço real:
pip install -e ".[mongodb]"
# para o backend SaaS opcional (DBBridge Cloud, ver seção abaixo):
pip install -e ".[server]"
```

## DBBridge Cloud (serviço hospedado)

Este repositório contém a **biblioteca open source completa** — tudo que ela faz é grátis, MIT,
para sempre, rodando 100% na sua máquina.

O [DBBridge Cloud](https://dbbridge.mytheria.com.br) é o serviço hospedado construído sobre esta
mesma engine, para quem quer o resultado sem operar ferramenta: interface web, análise assistida
por IA (com preço por request público), projetos por equipe, relatórios executivos exportáveis,
API keys e SDKs oficiais. O código da plataforma vive em repositório separado — este repo é, e
continuará sendo, só a biblioteca.

## Uso rápido

### Traduzir um schema

```bash
dbbridge translate --from sqlite --to postgres schema.sql
```

Casos que o parser/renderer não reconhecem com segurança viram `REVIEW_REQUIRED` no stderr — nunca
uma tradução inventada.

### Escanear um projeto Python

```bash
dbbridge scan --from sqlite --to postgres ./meu_projeto
```

Encontra `execute()`/`executemany()` com SQL potencialmente incompatível entre os dois dialetos:
placeholders (`?` vs `%s`), `sqlite_master`, `PRAGMA`, `INSERT OR IGNORE`/`OR REPLACE`,
case-sensitivity de `LIKE`, autoincrement, e mais.

### Migrar código-fonte automaticamente

```bash
dbbridge patch --from sqlite --to postgres ./meu_projeto   # dry-run, mostra o plano
dbbridge apply --from sqlite --to postgres ./meu_projeto   # aplica com backup automático
dbbridge rollback ./meu_projeto                            # desfaz, restaura do backup
```

Reescreve só literais de string simples sem ambiguidade (troca de placeholder). `f-strings`,
concatenação e casos ambíguos (aspas duplas, `INSERT OR REPLACE`, etc.) nunca são alterados
automaticamente — viram `REVIEW_REQUIRED`/`SKIPPED_COMPLEX_EXPRESSION` no plano.

### Migrar dados entre bancos de verdade

```bash
dbbridge migrate-data --from sqlite --to postgres \
    --source-dsn ./app.db --target-dsn "host=localhost dbname=app" --tables users leads
dbbridge validate --from sqlite --to postgres \
    --source-dsn ./app.db --target-dsn "host=localhost dbname=app" --tables users leads
```

Copia em lotes, nunca faz `DROP`/`TRUNCATE`, sempre acrescenta. `validate` compara contagens e
checksum (SHA-256) linha a linha quando a tabela é pequena o bastante. Pra rodar schema + dados +
validação num comando só, use `execute-plan --apply-schema --source-dsn ... --tables ...` (ver
abaixo).

### Planejar e simular uma transição de stack

```bash
dbbridge targets --json
dbbridge billing-plan --json
dbbridge plan --from sqlite --to mysql schema.sql --json
dbbridge plan --from sqlite --to mongodb schema.sql
dbbridge simulate --from postgres --to mongodb \
    --plan migration-plan.json \
    --target-uri mongodb://localhost:27017 \
    --temporary-database dbbridge_simulation
dbbridge execute-plan --from sqlite --to sqlite schema.sql --json
dbbridge execute-plan --from sqlite --to sqlite schema.sql --apply-schema --target-dsn ./target.db
dbbridge execute-plan --from sqlite --to postgres schema.sql \
    --apply-schema --target-dsn "host=localhost dbname=app" \
    --source-dsn ./app.db --tables users leads --json
```

`plan` gera o plano semântico de transição de stack (schema + roteamento pra família de destino
certa — relacional, documento, grafo, chave-valor, wide-column ou busca) — sempre um preview primeiro,
nunca aplica nada sozinho. `execute-plan` executa esse plano: dry-run por padrão, schema real no
destino com `--apply-schema --target-dsn`, e com `--source-dsn`/`--tables` também migra os dados e
valida contagens/checksum na mesma chamada — schema, dados e validação de ponta a ponta, sem precisar
encadear `execute-plan` + `migrate-data` + `validate` manualmente.

Para destino documental (`--to mongodb`), `simulate` valida documentos em banco temporário ou em
memória (`memory://`) — com `dbbridgekit[mongodb]` instalado e uma URI real, conecta via PyMongo,
cria o database temporário, carrega amostras, cria índices, confere contagens e remove o database
no final, exceto quando `--keep-simulation` é usado. `apply` NoSQL continua bloqueado nesta fase.

`dbbridge targets` cobre todo o catálogo registrado (22 bancos) — cada campo (`apply_schema`,
`data_migration`, `production_ready`, etc.) é derivado mecanicamente do mesmo registro honesto de
`refactor/capabilities.py`, nunca uma segunda lista mantida à mão que pode divergir da real.

### Compatibility Mode (código antigo continua rodando)

```python
from dbbridge import connect

db = connect(source_dialect="sqlite", target_dialect="postgres", dsn="host=localhost dbname=app")
db.execute("SELECT * FROM users WHERE id=?", (1,))  # vira %s por baixo, roda no Postgres de verdade
```

Permite migrar a aplicação por partes: o código continua escrito na sintaxe de origem enquanto o
banco de verdade já é o destino — e não é só a sintaxe da query: o tratamento de erro também
continua igual, não importa qual banco está por trás:

```python
from dbbridge.errors import UniqueViolationError

try:
    db.execute("INSERT INTO users(email) VALUES (?)", (email,))
except UniqueViolationError:
    ...  # mesmo código não importa qual banco está por trás — troca de destino sem atrito
```

`target_dialect` aceita `"sqlite"`, `"postgres"`, `"mysql"`, `"duckdb"`, `"snowflake"` ou
`"sqlserver"` hoje (o mesmo `connect()`, só trocando essa string, sem mudar mais nada no resto do
código de cima).

## Exemplos executáveis

```bash
python examples/translate_schema.py         # traduz um schema via API Python
python examples/scan_and_patch_project.py    # scan -> patch -> apply -> rollback num mini-app
python examples/compat_mode.py                # Compatibility Mode de ponta a ponta
DBBRIDGE_EXAMPLE_PG_DSN="host=localhost dbname=..." python examples/full_data_migration.py
```

Todos os quatro rodam de verdade (não são pseudocódigo) — os três primeiros só precisam do SQLite
da stdlib; o último precisa de um PostgreSQL acessível via a variável de ambiente indicada.

## Arquitetura

```txt
dbbridge/
  cli.py                     # scan|report|translate|plan|advise|simulate|execute-plan|patch|apply|
                              # migrate-data|validate|rollback|targets|billing-plan|doctor|dialects
  core/
    ir.py                    # Schema, Table, Column, ForeignKey, UniqueConstraint, CheckConstraint, Index, View, Trigger, Enum
    types.py                 # CanonicalType, Ambiguity
    parser.py / renderer.py  # contratos + registry (register_parser/get_parser/available_parsers, idem renderer)
    planner.py                # translate(sql, source, target) — o pipeline completo numa função
    sql_lex.py                 # split respeitando parênteses/aspas, quoting defensivo de identificador reservado
  dialects/                   # 10 dialetos relacionais (sqlite, postgres, mysql, oracle, sqlserver,
                              # db2, duckdb, snowflake, bigquery, redshift) + dbf (fonte só-leitura) + redis (fonte)
  scanner/scanner.py           # AST — encontra SQL arriscado por par de dialetos
  codemod/codemod.py            # AST — reescreve só literais simples sem ambiguidade
  migration/
    schema_migration.py        # traduz + aplica DDL (aditivo, nunca DROP/TRUNCATE)
    data_migration.py           # copia dados em lotes
    validator.py                 # contagens + checksum
    rollback.py                   # restaura código a partir de backup
  compat/runtime.py             # connect() — Compatibility Mode (sqlite/postgres/mysql/duckdb/snowflake/sqlserver)
  reports/report.py              # normaliza qualquer resultado pra texto/JSON
  automation/planner.py          # plano semântico SQL->SQL e blueprints SQL->NoSQL
  automation/executor.py         # executor seguro: dry-run, gates de revisão e aplicação controlada
  automation/advisor.py          # readiness report + sugestões opcionais via OpenAI
  refactor/capabilities.py       # registro honesto de capacidade por banco (usado por `targets`/`plan`)
```

Por que IR em vez de conversores pareados: com N dialetos, um conversor direto por par cresce O(N²)
e duplica a mesma lógica de tipos/constraints em cada combinação. Com um modelo canônico no meio,
cada dialeto novo precisa de só 1 parser + 1 renderer (O(N)) pra já converter de/para todos os
outros já implementados.

## Segurança

- A biblioteca do cliente usa token próprio (`DBBRIDGE_CLIENT_TOKEN`) contra o seu backend; a chave
  OpenAI fica só no servidor (`OPENAI_API_KEY`), nunca distribuída junto da lib.
- Toda alteração de código gera backup antes de escrever, e pode ser revertida via `dbbridge rollback`.
- Migração de schema/dados é sempre aditiva — nunca `DROP`/`TRUNCATE`/`DELETE`.
- Casos ambíguos (aspas duplas em literal, `INSERT OR REPLACE`, f-strings, expressões dinâmicas)
  nunca são "adivinhados" — viram `REVIEW_REQUIRED` pra revisão manual.
- `apply_changes` verifica `ast.parse()` do arquivo resultante antes de considerar sucesso; se o
  resultado tiver `SyntaxError`, reverte sozinho a partir do backup.

## Fases

1. **IR + SQLite/PostgreSQL/MySQL/DuckDB `fully_supported`** — atual: parser/renderer real pra 10
   dialetos relacionais, scanner, codemod, migração de schema/dados, validação por checksum,
   rollback, CLI, Compatibility Mode (SQLite/PostgreSQL/MySQL/DuckDB/Snowflake/SQL Server),
   tradução de erro canônica (ver [docs/guide.md](docs/guide.md#tradução-de-erros)).
2. Ampliar a IR semântica para mais recursos SQL: schemas/namespaces, sequences, computed columns,
   partial indexes, collations, policies, stored procedures como artefatos de revisão e metadados
   físicos preserváveis.
3. Codemod genérico validado contra os dialetos comerciais.
4. Data migration validada nos pares centrais SQLite/Postgres/MySQL.
5. ~~Adaptador de execução real para MySQL no Compatibility Mode~~ — **feito** (`connect()` via
   PyMySQL, extra `[mysql]`).
6. **Fases futuras (levantadas, ainda não priorizadas):** shadow migration (rodar origem e destino
   em paralelo comparando resultados antes do cutover final), query replay (reproduzir tráfego real
   de produção contra o destino como teste de carga/compatibilidade), dashboard web, relatórios em
   HTML/PDF (hoje só texto/JSON via `reports/report.py`), mecanismo de plugin formal pra dialetos
   externos (hoje a extensão já é possível via `register_parser`/`register_renderer` — falta só
   empacotar como plugin instalável separadamente, ex. entry points do Python). Suporte NoSQL
   (MongoDB) já tem blueprint + simulação real via PyMongo em `automation/mongodb.py` — apply em
   produção continua bloqueado até existir cutover controlado (ver
   [docs/compatibility-matrix.md](docs/compatibility-matrix.md)).

Cada fase só avança depois da anterior validada — ver [docs/guide.md](docs/guide.md) para detalhes
de arquitetura e extensão pra novos dialetos, [docs/cli-reference.md](docs/cli-reference.md) pra
todos os comandos, [docs/compatibility-matrix.md](docs/compatibility-matrix.md) pro que já
funciona vs. planejado, [docs/migration-tutorial.md](docs/migration-tutorial.md) pro passo a passo
completo, e [docs/production-checklist.md](docs/production-checklist.md) antes de rodar contra
dados reais.
