Skip to content

Commit 5f2925a

Browse files
committed
docs cleanup, appender api cleanup
1 parent 917a962 commit 5f2925a

10 files changed

Lines changed: 310 additions & 243 deletions

File tree

README.md

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Package Version](https://img.shields.io/hexpm/v/duckling)](https://hex.pm/packages/duckling)
44
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/duckling/)
55

6-
Gleam bindings for [DuckDB](https://duckdb.org/).
6+
Gleam bindings for [DuckDB](https://duckdb.org/) on the Erlang runtime.
77

88
## Quickstart
99

@@ -15,15 +15,17 @@ gleam add duckling@1
1515
Run:
1616
```gleam
1717
import duckling
18+
import duckling/param
19+
import gleam/dict
1820
1921
pub fn main() {
2022
use db <- duckling.with_database("foo.duckdb", dict.new())
2123
use conn <- duckling.with_connection(db)
2224
use res <- result.try(duckling.query(
2325
"SELECT ? + ?",
26+
with: [param.int(1), param.int(2)],
27+
expecting: duckling.TupleDecoder(decode.at([0], decode.int)),
2428
on: conn,
25-
with: [duckling.int(1), duckling.int(2)],
26-
expecting: decode.at([0], decode.int)
2729
))
2830
assert res == [3]
2931
}
@@ -34,48 +36,52 @@ Further documentation can be found at <https://hexdocs.pm/duckling>.
3436
## Features and Roadmap
3537

3638
This library currently implements the full capabilities exposed by the
37-
[educkdb](https://github.com/mmzeeman/educkdb) bindings. Javascript bindings are
38-
planned, but not implemented at this time.
39+
[educkdb](https://github.com/mmzeeman/educkdb) bindings.
3940

4041
* [x] Query API
4142
* [-] Bound Parameters [1](#footnote-1)
4243
* [x] Positional Parameters
43-
* [ ] Named Parameters
44-
* [ ] Blob
45-
* [x] Boolean
46-
* [x] Date
47-
* [ ] Decimal
48-
* [x] Double
49-
* [ ] Enum
50-
* [x] Float
51-
* [ ] Int128
52-
* [x] Int16
53-
* [x] Int64
54-
* [x] Int8
55-
* [x] Int32
56-
* [ ] Interval
57-
* [ ] Json
58-
* [ ] List
59-
* [ ] Map
60-
* [ ] Struct
61-
* [x] Time
62-
* [x] Timestamp
63-
* [x] TimestampMs
64-
* [x] TimestampNs
65-
* [x] TimestampS
66-
* [ ] UInt128
67-
* [x] UInt16
68-
* [x] UInt64
69-
* [x] UInt8
70-
* [x] UInt32
71-
* [ ] Uuid
72-
* [x] Varchar
44+
* [x] Named Parameters
45+
* [ ] Blob type
46+
* [x] Boolean type
47+
* [x] Date type
48+
* [ ] Decimal type
49+
* [x] Double type
50+
* [ ] Enum type
51+
* [x] Float type
52+
* [ ] Int128 type
53+
* [x] Int16 type
54+
* [x] Int64 type
55+
* [x] Int8 type
56+
* [x] Int32 type
57+
* [ ] Interval type
58+
* [ ] Json type
59+
* [ ] List type
60+
* [ ] Map type
61+
* [ ] Struct type
62+
* [x] Time type
63+
* [x] Timestamp type
64+
* [x] TimestampMs type
65+
* [x] TimestampNs type
66+
* [x] TimestampS type
67+
* [ ] UInt128 type
68+
* [x] UInt16 type
69+
* [x] UInt64 type
70+
* [x] UInt8 type
71+
* [x] UInt32 type
72+
* [ ] Uuid type
73+
* [x] Varchar type
7374
* [x] Iterator / Chunk API
7475
* [ ] Logical Column Type API [2](#footnote-2)
75-
* [ ] Appender API (in progress)
76+
* [x] Appender API
7677
* [x] Erlang Backend (educkdb)
77-
* [ ] Javascript Backend
78-
* [ ] WASM backend for browser support
78+
* [ ] Improved compilation times
79+
80+
## Version Table
81+
82+
| duckling | educkdb | DuckDB |
83+
| -------- | ------- | ------ |
84+
| 1.0.0 | 0.9.10 | 1.3.1 |
7985

8086
## Footnotes
8187

gleam.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ version = "1.0.0"
1414

1515
internal_modules = [
1616
"duckling/ffi/*",
17-
"duckling/internal",
1817
"duckling/internal/*",
1918
]
2019

src/duckling.gleam

Lines changed: 68 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,28 @@ import gleam/erlang/charlist
1212
import gleam/list
1313
import gleam/result
1414

15-
// helper type aliases
15+
/// Specifies how output data is decoded. With the TupleDecoder the dynamic
16+
/// object passed to the decoder is indexable by integer field offsets. An object
17+
/// with named fields with the names of the output columns is passed to
18+
/// NamedDecoders.
19+
pub type RowDecoder(t) {
20+
TupleDecoder(Decoder(t))
21+
NamedDecoder(Decoder(t))
22+
}
1623

24+
/// Three element tuple representing a time of day made of hour, minute, and
25+
/// decond fields. This type is used for representing times in query parameters
26+
/// and output data.
1727
pub type TimeData =
1828
types.TimeData
1929

30+
/// Three element tuple of a date year, month, and day as integers. This type is
31+
/// used for representing dates in query parameters and output data.
2032
pub type DateData =
2133
types.DateData
2234

23-
// Connections
24-
25-
/// Open, or create a duckdb database file
35+
/// Open, or create a duckdb database file. We recommend using the with_database
36+
/// function instead to ensure the database is closed properly after use.
2637
pub fn open(
2738
filename: String,
2839
options: Dict(String, String),
@@ -38,21 +49,25 @@ pub fn open(
3849
|> result.map(types.Database)
3950
}
4051

41-
/// Connect to the database.
42-
/// Note: It is adviced to use the connection in a single process.
52+
/// Connect to the database. We recommend using the with_connection function
53+
/// instead to ensure the connection is closed after use.
54+
///
55+
/// > Note: It is adviced to use the connection in a single process.
4356
pub fn connect(database: Database) -> Result(Connection, DuckdbError) {
4457
educkdb.connect(database.ref)
4558
|> result.map_error(error.ConnectionError)
4659
|> result.map(types.Connection)
4760
}
4861

49-
/// Disconnect from the database.
62+
/// Disconnect from the database. Used to cleanup a database handle created by
63+
/// [open](#open).
5064
pub fn disconnect(conn: Connection) -> Result(Nil, DuckdbError) {
5165
educkdb.disconnect(conn.ref)
5266
|> helper.decode_ok_or_error(error.ConnectionError)
5367
}
5468

55-
/// Close the database. All open connections will become unusable.
69+
/// Close the database. All open connections will become unusable. Used to
70+
/// cleanup a connection created by [connect](#connect).
5671
pub fn close(database: Database) -> Result(Nil, DuckdbError) {
5772
let types.Database(raw_db) = database
5873
educkdb.close(raw_db)
@@ -101,37 +116,44 @@ pub fn with_connection(
101116
Ok(res)
102117
}
103118

104-
// Queries
105-
106-
/// Query the database. The answer is returned immediately.
107-
// fn internal_query(sql: String, conn: Connection) -> Result(QueryResult, DuckdbError) {
108-
// educkdb.query(conn.ref, sql)
109-
// |> result.map_error(QueryError)
110-
// |> result.map(QueryResult)
111-
// }
112-
113-
// Execute a SQL query and fetch all results, unpacking each row tuple using
114-
// the given decoder.
115-
//
116-
// Example:
117-
// ```gleam
118-
// import duckling/param
119-
//
120-
// type User {
121-
// User(
122-
// user_id: Int,
123-
// name: String,
124-
// birthday: #(Int, Int, Int)
125-
// )
126-
// }
127-
//
128-
// pub fn main() {
129-
// let decoder = {
130-
// use user_id <- decode.field(0, decode.int)
131-
// use name <-
132-
// }
133-
// }
134-
// ```
119+
/// Execute a SQL query and fetch all results, unpacking each row using
120+
/// the given decoder.
121+
///
122+
/// Example:
123+
/// ```gleam
124+
/// import duckling
125+
/// import duckling/param
126+
/// import gleam/dict
127+
///
128+
/// type User {
129+
/// User(
130+
/// user_id: Int,
131+
/// name: String,
132+
/// birthday: #(Int, Int, Int)
133+
/// )
134+
/// }
135+
///
136+
/// decode_user_row() -> RowDecoder(User) {
137+
/// TupleDecoder({
138+
/// use user_id <- decode.field(0, decode.int)
139+
/// use name <- decode.field(1, decode.string)
140+
/// use birthday <- decode.field(2, duckling.decode_date())
141+
/// decode.success(User(user_id, name, birthday))
142+
/// })
143+
/// }
144+
///
145+
/// pub fn main() {
146+
/// use db <- duckling.with_database("database.duckdb", dict.new())
147+
/// use conn <- duckling.with_connection(db)
148+
/// use users <- result.try(duckling.query(
149+
/// "SELECT * FROM users;",
150+
/// param.empty,
151+
/// decode_user_row(),
152+
/// conn,
153+
/// ))
154+
/// echo users
155+
/// }
156+
/// ```
135157
pub fn query(
136158
sql: String,
137159
with params: param.Params,
@@ -159,37 +181,25 @@ pub fn query(
159181
/// Execute a SQL query without returning any results.
160182
pub fn execute(
161183
sql: String,
162-
on connection: Connection,
163184
with params: Params,
185+
on connection: Connection,
164186
) -> Result(Nil, DuckdbError) {
165187
use prepped <- result.try(stmt.prepare(sql, connection))
166188
use _ <- result.try(stmt.bind_params(prepped, params))
167189
stmt.execute_prepared(prepped)
168190
|> result.replace(Nil)
169191
}
170192

171-
//
172-
// Results
173-
//
174-
175-
//
176-
// Chunks
177-
//
178-
179-
//
180-
// Decoders
181-
//
182-
183-
// Specifies whether output
184-
pub type RowDecoder(t) {
185-
TupleDecoder(Decoder(t))
186-
NamedDecoder(Decoder(t))
187-
}
188-
193+
/// Helper for decoding a TIME field into [TimeData](#TimeData)
189194
pub const decode_time = base_type.decode_time
190195

196+
/// Helper for decoding a DATE field into [DateData](#DateData)
191197
pub const decode_date = base_type.decode_date
192198

199+
/// Helper for decoding a TIMESTAMP field into a 2 element tuple of
200+
///`#(DateData, TimeData)`
193201
pub const decode_timestamp = base_type.decode_timestamp
194202

203+
/// Helper for decoding a field that maybe nullable into an Option(t) of its
204+
/// base type.
195205
pub const decode_nullable = base_type.decode_nullable

0 commit comments

Comments
 (0)