Cada motor
O que a interface comum cobre, e o que só existe em cada um.
A interface comum cobre o que faz sentido em todos: conectar, consultar, fechar. O resto cada motor expõe pelo que ele é — um ORM que finge que Redis é uma tabela produz código que parece portável e não é.
SQLite#
Roda dentro do processo. É o banco de teste que não deixa rastro:
adopt Forge
db := Forge.memoria() // ou Forge.conectar("dados.db")
Forge.executar(db, "create table t (id integer primary key, n integer)")
Forge.de(db, "t").inserir({"n": 1})
assert Forge.de(db, "t").contar() is 1Duas coisas que o Forge liga e o SQLite deixa desligadas por padrão: chave estrangeira (senão a restrição existe só no papel) e WAL (senão um leitor bloqueia o escritor, e um servidor trava com carga leve).
PostgreSQL#
Os tipos voltam convertidos: jsonb vira vault, array vira cluster, boolean vira yes/no.
// db := Forge.conectar("postgres://usuario:senha@localhost/app")
//
// Forge.executar(db, """
// create table pessoas (
// id serial primary key,
// nome text not null,
// dados jsonb,
// tags text[]
// )
// """)
//
// Forge.executar(db,
// "insert into pessoas (nome, dados, tags) values (?, ?, ?)",
// ["Ana", {"cor": "azul"}, ["a", "b"]])
//
// linha := Forge.primeiro(db, "select * from pessoas")
// out linha["dados"]["cor"] // "azul" — vault de verdade
// out linha["tags"][0] // "a" — cluster de verdadeRETURNING funciona e devolve as linhas:
// nova := Forge.executar(db,
// "insert into pessoas (nome) values (?) returning id, nome",
// ["Bia"])
// out nova[0]["id"]MySQL e MariaDB#
O mesmo driver serve os dois — o MariaDB nasceu de um fork e manteve o protocolo. O que muda é a autenticação padrão.
// db := Forge.conectar("mysql://root:senha@localhost/app")
// out db.ultimo_id() // o id gerado pelo último auto_incrementRedis#
Não tem SQL, e fingir que tem seria mentir. O que ele tem é chave-valor, e é isso que a interface expõe:
// db := Forge.conectar("redis://localhost")
//
// db.comando("SET", "usuario:1", "Ana")
// out db.comando("GET", "usuario:1")
// db.comando("EXPIRE", "usuario:1", 60)
//
// db.comando("RPUSH", "fila", 1, 2, 3)
// out db.comando("LRANGE", "fila", 0, -1)Pipeline é a otimização mais eficaz com Redis. Cem comandos em cem idas custam cem vezes a latência da rede; numa ida só, custam uma:
// respostas := db.pipeline([
// ["SET", "a", "1"],
// ["SET", "b", "2"],
// ["MGET", "a", "b"]
// ])
// out respostas[2] // ["1", "2"]MongoDB#
Documentos, não tabelas. O _id sai como texto e a busca por ele aceita texto — sem essa conversão, procurar por id nunca acharia nada, e não haveria erro, só um resultado vazio:
// db := Forge.conectar("mongodb://localhost/app")
//
// r := db.inserir("pessoas", [
// {"nome": "Ana", "idade": 30},
// {"nome": "Bia", "idade": 25}
// ])
//
// out db.achar("pessoas", {"idade": {"$gt": 26}})
// out db.achar_um("pessoas", {"_id": r["ids"][0]})
// db.atualizar("pessoas", {"nome": "Bia"}, {"idade": 26})
// out db.contar("pessoas")
//
// out db.agregar("pessoas", [
// {"$group": {"_id": void, "media": {"$avg": "$idade"}}}
// ])
//
// db.criar_indice("pessoas", "nome", unico := yes)O que é comum a todos#
| SQLite | Postgres | MySQL | Redis | Mongo | |
|---|---|---|---|---|---|
conectar | ✓ | ✓ | ✓ | ✓ | ✓ |
ping, versao, fechar | ✓ | ✓ | ✓ | ✓ | ✓ |
consultar / executar | ✓ | ✓ | ✓ | cru | documento |
| construtor de consultas | ✓ | ✓ | ✓ | — | — |
| ORM | ✓ | ✓ | ✓ | — | — |
| transações | ✓ | ✓ | ✓ | MULTI | — |
tabelas / colunas | ✓ | ✓ | ✓ | — | colecoes |