type User { id: Int, name: Str }
query findUser(name: Str): User[dyn] {
SELECT id, name FROM users WHERE name = {name}
}
proc lookUp(db: hive.sql.SqlConnection, name: Str): Str {
if hive.sql.run(db, findUser(name)) is Result.Ok(rows) {
if rows bounds 0 {
return rows[0].name
}
}
return "?"
}
proc main(): void {
// Um ":memory:" simples daria a cada uma destas oito conexões um banco
// privado e vazio, só dela. O cache compartilhado é o que faz todas
// elas serem o mesmo banco.
opened := hive.sql.pool(hive.sql.DatabaseDriver.SQLite(), "file::memory:?cache=shared", 8, 1)
if opened is Result.Ok(db) {
hive.sql.raw(db, "CREATE TABLE users (id INTEGER, name TEXT)")
hive.sql.raw(db, "INSERT INTO users (id, name) VALUES (1, 'ada'), (2, 'grace')")
echo await [lookUp(db, "ada"), lookUp(db, "grace")]
hive.sql.close(db)
}
}Um banco SQLite :memory: simples pertence à conexão, não ao processo: cada conexão ganha um banco privado e vazio que some quando ela fecha. connect e pool abrem ambos um pool de conexões, então isso tem um canto afiado. Uma query por vez funciona; várias ao mesmo tempo não — o pool abre mais conexões, cada uma cai num banco próprio, e as queries que foram para as novas voltam com "no such table". Um programa que passa em todo teste com uma query por vez começa a falhar no momento em que as requisições se sobrepõem, que é exatamente o que acontece atrás de um servidor HTTP.
Há duas saídas, e uma delas é a resposta de verdade. pool(…, 1, 1) limita o pool a uma conexão só, o que funciona mas faz toda query do programa passar por ela uma de cada vez. "file::memory:?cache=shared" é a que se deve usar: as conexões compartilham um único banco em memória, então o pool pode ser tão largo quanto o trabalho. Nada disso é regra do Hive — é do SQLite — mas vale saber antes que a produção ensine.