Something went wrong. Try again.
A Gleam DuckDB CLI wrapper
Something went wrong. Try again.
Files
- Gleam 83%
- Erlang 17%
README.md
qwak #
qwak is a wrapper for the DuckDB CLI for Gleam. For now only works in Erlang, but if there's interest a Node version may be added.
Installation #
It's not in Hex yet, so to use it, add the library's git repo URI to your gleam.toml:
[dependencies]
qwak = { git = "https://tangled.org/josm.me/qwak", ref = "main" }
Usage #
import gleam/dynamic/decode
import gleam/erlang/process
import gleam/option.{type Option, None}
import gleam/otp/actor
import gleam/time/calendar
import qwak
pub type Artist {
Artist(
name: String,
genres: List(String),
location: String,
started: calendar.Date,
ended: Option(calendar.Date),
)
}
pub fn main() {
let name = process.new_name("qwak")
let config = qwak.default_config()
let assert Ok(actor.Started(_, conn)) = qwak.start(name, config)
let assert Ok(_) =
qwak.query(
"create table artists (
name text not null
, genres text[] not null
, location text not null
, started date not null
, ended date
);
",
)
|> qwak.run(conn)
let assert Ok(_) =
qwak.query(
"insert into artists (name, genres, location, started, ended) values
('Say Sue Me', ['surf rock', 'shoegaze'], 'Busan, South Korea', '2012-06-01', null)
, ('Cactus For Breakfast', ['surf rock', 'psych rock'], 'Berlin, Germany', '2024-02-01', null)
, ('The Cranberries', ['dream pop', 'post punk'], 'Limerick, Ireland', '1989-05-01', '2019-04-26')
, ('Fazerdaze', ['dream pop', 'bedroom pop'], 'New Zealand', '2014-08-01', null)
, ('Leenalchi', ['pansori pop'], 'Seoul, South Korea', '2019-01-01', null)
;",
)
|> qwak.run(conn)
let artist_decoder = {
use name <- decode.field("name", decode.string)
use genres <- decode.field("genres", decode.list(decode.string))
use location <- decode.field("location", decode.string)
use started <- decode.field("started", qwak.date_decoder())
use ended <- decode.field("ended", decode.optional(qwak.date_decoder()))
decode.success(Artist(name:, genres:, location:, started:, ended:))
}
let assert Ok(qwak.Rows(rows)) =
qwak.query("select * from artists where ended is null")
|> qwak.with_decoder(artist_decoder)
|> qwak.run(conn)
assert rows == [
Artist("Say Sue Me", ["surf rock", "shoegaze"], "Busan, South Korea", calendar.Date(2012, calendar.June, 1), None),
Artist("Cactus For Breakfast", ["surf rock", "psych rock"], "Berlin, Germany", calendar.Date(2024, calendar.February, 1), None),
Artist("Fazerdaze", ["dream pop", "bedroom pop"], "New Zealand", calendar.Date(2014, calendar.August, 1), None),
Artist("Leenalchi", ["pansori pop"], "Seoul, South Korea", calendar.Date(2019, calendar.January, 1), None),
]
}
Within an application #
You can create a supervisor qwak actor using qwak.supervised(), and add it to the rest of your supervision tree before anything that needs to use it:
import qwak
import gleam/erlang/process
import my/server
pub fn main() {
let name = process.new_name("qwak")
let config = qwak.default_config()
let duckdb = qwak.supervised(name, config)
let connection = qwak.connection_from_name(name)
let ctx = server.Context(connection)
let server = server.supervised(ctx)
let assert Ok(supervisor) =
supervisor.new(supervisor.RestForOne)
|> supervisor.add(duckdb)
|> supervisor.add(server)
|> supervisor.start
}
You can then use it in your request handlers:
fn handle_query(ctx: Context) {
let Context(connection) = ctx
let result qwak.query("select * from artists where ended is null")
|> qwak.with_decoder(artist_decoder)
|> qwak.run(conn)
case result {
Ok(qwak.Rows(rows)) -> display_table(rows)
Error(e) -> display_error(e)
}
}
Further documentation can be found at https://hexdocs.pm/qwak.
Development #
gleam run # Run the project
gleam test # Run the tests