# ducky

Native DuckDB driver for Gleam.

[![Package Version](https://img.shields.io/hexpm/v/ducky)](https://hex.pm/packages/ducky)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/ducky/)

## Install

```sh
gleam add ducky
```

## Quick start

Build a query with `sql`, run it with `run`:

```gleam
import ducky
import gleam/io
import gleam/result

pub fn main() {
  use conn <- ducky.with_connection(":memory:")

  use _ <- result.try(
    ducky.sql("CREATE TABLE ducks (name TEXT, quack_volume INT)")
    |> ducky.run(conn),
  )
  use _ <- result.try(
    ducky.sql("INSERT INTO ducks VALUES ('Duck Norris', 100)")
    |> ducky.run(conn),
  )

  use loud <- result.map(
    ducky.sql("SELECT name FROM ducks ORDER BY quack_volume DESC LIMIT 1")
    |> ducky.run(conn),
  )

  case loud.rows {
    [ducky.Row([ducky.Text(name), ..])] -> io.println(name <> " wins!")
    _ -> io.println("The pond is empty...")
  }
}
// => Duck Norris wins!
```

## Typed rows with decoders

For real applications, attach a decoder to get back your own types instead of
raw `Row` values:

```gleam
import ducky
import gleam/dynamic/decode

pub type Duck {
  Duck(name: String, quack_volume: Int)
}

pub fn loudest(conn) {
  let duck_decoder = {
    use name <- decode.field(0, decode.string)
    use quack_volume <- decode.field(1, decode.int)
    decode.success(Duck(name:, quack_volume:))
  }

  ducky.sql("SELECT name, quack_volume FROM ducks ORDER BY quack_volume DESC")
  |> ducky.returning(duck_decoder)
  |> ducky.run(conn)
  // => Ok(Returned(count: N, rows: [Duck("Duck Norris", 100), ...]))
}
```

See [examples/](https://github.com/lemorage/ducky/tree/master/examples) for complete usage patterns.

## License

Apache-2.0
