An open API service indexing awesome lists of open source software.

https://github.com/firetiger-oss/go-duckfs

DuckDB virtual file system based on io/fs
https://github.com/firetiger-oss/go-duckfs

duckdb duckdb-extension filesystem go golang sandbox

Last synced: 2 months ago
JSON representation

DuckDB virtual file system based on io/fs

Awesome Lists containing this project

README

          

# go-duckfs [![Go Reference](https://pkg.go.dev/badge/github.com/firetiger-oss/go-duckfs.svg)](https://pkg.go.dev/github.com/firetiger-oss/go-duckfs)


go-duckfs logo

DuckDB virtual file system based on io/fs

## Motivation

The purpose of this package is to allow Go programs to mount `io/fs` read-only
file systems as backend for DuckDB databases. It guarantees that all I/O will be
executed by the Go runtime instead of being performed directly by DuckDB.

DuckDB has extensions such as `httpfs` or `aws` to integrate the query engine
with data sets available over the network, but those are implemented in C++,
they don't share the same I/O stack as the rest of a Go application, and this
duality introduces challenges when it comes to instrumentation, access control,
or performance.

By sandboxing DuckDB via a _Virtual File System_, the `go-duckfs` package
bridges all I/O operations back into the Go application to leverage pure Go
packages like `net/http`, cloud vendor native SDKs, telemetry wrappers, etc...

## Building

The package requires C++ symbols that are not present in the go-duckdb static
build. The recommended way to install DuckDB is via [pixi](https://pixi.sh):

```bash
# Install DuckDB library
pixi install --locked

# Build with dynamic linking
CGO_ENABLED=1 \
CGO_LDFLAGS="-L.pixi/envs/default/lib" \
go build -tags=duckdb_use_lib
```

The Go program must be compiled using the `duckdb_use_lib` tag to select the
version of the DuckDB Go bindings suited for dynamic linking.

See also: https://github.com/duckdb/duckdb-go?tab=readme-ov-file#linking-a-dynamic-library

## Testing

Since `go test` builds the program from sources, it is necessary to set the
CGO environment variables and build tags:

```bash
CGO_ENABLED=1 \
CGO_LDFLAGS="-L.pixi/envs/default/lib" \
LD_LIBRARY_PATH=".pixi/envs/default/lib" \
go test -v ./... -tags=duckdb_use_lib
```

## Usage

The package exposes functions to create connectors for DuckDB instances with
a `fs.FS` as virtual file system, which can then be used to create a `sql.DB`.

### Basic Example

```go
c, err := duckfs.Open("", nil, os.DirFS("testdata"))
if err != nil {
log.Fatal(err)
}

db := sql.OpenDB(c)
defer db.Close()

// Query files using DuckDB's read functions
rows, err := db.Query(`SELECT * FROM read_parquet('data.parquet')`)
```

### Protocol-Aware Filesystem

Virtual paths use a protocol prefix (e.g., `test://file.parquet`). To handle
these paths, wrap your `fs.FS` to strip the protocol prefix:

```go
type myFS struct {
fsys fs.FS
}

func (f *myFS) Open(name string) (fs.File, error) {
// Strip protocol prefix if present
name = strings.TrimPrefix(name, "myproto://")
return f.fsys.Open(name)
}
```

Then use it with DuckDB queries:

```go
c, err := duckfs.Open("", nil, &myFS{fsys: os.DirFS("data")})
if err != nil {
log.Fatal(err)
}

db := sql.OpenDB(c)
defer db.Close()

// Query using protocol prefix
row := db.QueryRow(`SELECT * FROM read_csv('myproto://records.csv')`)
```

## Contributing

Contributions are welcome! To get started:

1. Ensure you have Go 1.24.0+ and [pixi](https://pixi.sh) installed
2. Run `pixi install --locked` to install the DuckDB library
3. Run tests using the commands in the [Testing](#testing) section

Please report bugs and feature requests via [GitHub Issues](https://github.com/firetiger-oss/go-duckfs/issues).

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.