Skip to content

Commit

Permalink
Refactor to use driver.Conn instead of any.
Browse files Browse the repository at this point in the history
  • Loading branch information
marcboeker committed Jan 15, 2024
1 parent fffcf07 commit 1ca5141
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 365 deletions.
162 changes: 48 additions & 114 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,131 +70,65 @@ Please refer to the [database/sql](https://godoc.org/database/sql) GoDoc for fur
If you want to use the [DuckDB Appender API](https://duckdb.org/docs/data/appender.html), you can obtain a new Appender by supplying a DuckDB connection to `NewAppenderFromConn()`.

```go
package main

import (
"context"
"database/sql"

"github.com/marcboeker/go-duckdb"
)

func main() {
connector, err := duckdb.OpenConnector("test.db", nil)
if err != nil {
panic(err)
}
driverConn, err := connector.Connect(context.Background())
if err != nil {
panic(err)
}
defer driverConn.Close()

// Retrieve appender from connection (note that you have to create the table 'test' beforehand).
appender, err := duckdb.NewAppenderFromConn(driverConn, "", "test")
if err != nil {
panic(err)
}
defer appender.Close()

err = appender.AppendRow(1, "a")
if err != nil {
panic(err)
}

// Optional, if you want to access the appended rows immediately.
err = appender.Flush()
if err != nil {
panic(err)
}

// Alternatively, you can use Raw method of sql.Conn to obtain the driver connection.
db, err := sql.Open("duckdb", "")
if err != nil {
panic(err)
}
defer db.Close()

conn, err := db.Conn(context.Background())
if err != nil {
panic(err)
}
defer conn.Close()

err = conn.Raw(func(driverConn any) error {
// Notice usage of driverConn
appender, err := duckdb.NewAppenderFromConn(driverConn, "", "test")
if err != nil {
panic(err)
}
defer appender.Close()

err = appender.AppendRow(...)
if err != nil {
panic(err)
}

return nil
})
if err != nil {
panic(err)
}
connector, err := duckdb.NewConnector("test.db", nil)
if err != nil {
...
}
conn, err := connector.Connect(context.Background())
if err != nil {
...
}
defer conn.Close()

// Retrieve appender from connection (note that you have to create the table 'test' beforehand).
appender, err := NewAppenderFromConn(conn, "", "test")
if err != nil {
...
}
defer appender.Close()

err = appender.AppendRow(...)
if err != nil {
...
}

// Optional, if you want to access the appended rows immediately.
err = appender.Flush()
if err != nil {
...
}
```

## DuckDB Apache Arrow Interface

If you want to use the [DuckDB Arrow Interface](https://duckdb.org/docs/api/c/api#arrow-interface), you can obtain a new Arrow by supplying a DuckDB connection to `NewArrowFromConn()`.

```go
package main

import (
"context"
"database/sql"

"github.com/marcboeker/go-duckdb"
)

func main() {
db, err := sql.Open("duckdb", "")
if err != nil {
panic(err)
}
defer db.Close()

conn, err := db.Conn(context.Background())
if err != nil {
panic(err)
}
defer conn.Close()

// Use Raw method of sql.Conn to obtain the driver connection.
err = conn.Raw(func(driverConn any) error {
// Create Arrow interface from the connection.
ar, err := duckdb.NewArrowFromConn(driverConn)
if err != nil {
panic(err)
}

rdr, err := ar.Query(context.Background(), "SELECT * FROM generate_series(1, 10)")
if err != nil {
panic(err)
}
defer rdr.Release()

for rdr.Next() {
// Process records.
}

return nil
})
if err != nil {
panic(err)
}
connector, err := duckdb.NewConnector("", nil)
if err != nil {
...
}
conn, err := connector.Connect(context.Background())
if err != nil {
...
}
defer conn.Close()

// Retrieve Arrow from connection.
ar, err := duckdb.NewArrowFromConn(conn)
if err != nil {
...
}

rdr, err := ar.QueryContext(context.Background(), "SELECT * FROM generate_series(1, 10)")
if err != nil {
...
}
defer rdr.Release()

for rdr.Next() {
// Process records.
}
```

## Linking DuckDB
Expand Down
4 changes: 2 additions & 2 deletions appender.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type Appender struct {
}

// NewAppenderFromConn returns a new Appender from a DuckDB driver connection.
func NewAppenderFromConn(driverConn any, schema, table string) (*Appender, error) {
func NewAppenderFromConn(driverConn driver.Conn, schema string, table string) (*Appender, error) {
dbConn, ok := driverConn.(*conn)
if !ok {
return nil, fmt.Errorf("not a duckdb driver connection")
Expand All @@ -40,7 +40,7 @@ func NewAppenderFromConn(driverConn any, schema, table string) (*Appender, error
panic("database/sql/driver: misuse of duckdb driver: Appender after Close")
}

var schemastr *C.char
var schemastr *(C.char)
if schema != "" {
schemastr = C.CString(schema)
defer C.free(unsafe.Pointer(schemastr))
Expand Down
74 changes: 27 additions & 47 deletions appender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +57,13 @@ func randString(n int) string {
}

func TestAppender(t *testing.T) {
connector, err := OpenConnector("", nil)
c, err := NewConnector("", nil)
require.NoError(t, err)
defer connector.Close()

db := sql.OpenDB(connector)
db := sql.OpenDB(c)
createAppenderTable(db, t)
defer db.Close()

// Test that appender can be opened from the connector directly
driverConn, err := connector.Connect(context.Background())
require.NoError(t, err)

appender, err := NewAppenderFromConn(driverConn, "", "test")
require.NoError(t, err)

err = appender.Close()
require.NoError(t, err)

err = driverConn.Close()
require.NoError(t, err)

type dataRow struct {
ID int
UInt8 uint8
Expand Down Expand Up @@ -117,45 +103,39 @@ func TestAppender(t *testing.T) {
Bool: randBool(),
}
}
var rows []dataRow
rows := []dataRow{}
for i := 0; i < numAppenderTestRows; i++ {
rows = append(rows, randRow(i))
}

conn, err := db.Conn(context.Background())
conn, err := c.Connect(context.Background())
require.NoError(t, err)
defer conn.Close()

err = conn.Raw(func(driverConn any) error {
appender, err := NewAppenderFromConn(driverConn, "", "test")
require.NoError(t, err)
defer appender.Close()

for _, row := range rows {
err := appender.AppendRow(
row.ID,
row.UInt8,
row.Int8,
row.UInt16,
row.Int16,
row.UInt32,
row.Int32,
row.UInt64,
row.Int64,
row.Timestamp,
row.Float,
row.Double,
row.String,
row.Bool,
)
require.NoError(t, err)
}

err = appender.Flush()
appender, err := NewAppenderFromConn(conn, "", "test")
require.NoError(t, err)
defer appender.Close()

for _, row := range rows {
err := appender.AppendRow(
row.ID,
row.UInt8,
row.Int8,
row.UInt16,
row.Int16,
row.UInt32,
row.Int32,
row.UInt64,
row.Int64,
row.Timestamp,
row.Float,
row.Double,
row.String,
row.Bool,
)
require.NoError(t, err)

return nil
})
}
err = appender.Flush()
require.NoError(t, err)

res, err := db.QueryContext(
Expand Down
Loading

0 comments on commit 1ca5141

Please sign in to comment.