@@ -12,17 +12,28 @@ import gleam/erlang/charlist
1212import gleam/list
1313import 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.
1727pub 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.
2032pub 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.
2637pub 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.
4356pub 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).
5064pub 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).
5671pub 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+ /// ```
135157pub 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.
160182pub 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)
189194pub const decode_time = base_type . decode_time
190195
196+ /// Helper for decoding a DATE field into [DateData](#DateData)
191197pub const decode_date = base_type . decode_date
192198
199+ /// Helper for decoding a TIMESTAMP field into a 2 element tuple of
200+ ///`#(DateData, TimeData)`
193201pub 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.
195205pub const decode_nullable = base_type . decode_nullable
0 commit comments