duckdb_dart 0.3.6 copy "duckdb_dart: ^0.3.6" to clipboard
duckdb_dart: ^0.3.6 copied to clipboard

A DuckDB client for Dart

A Dart client API to DuckDb

Features #

Sending and executing statements works. Fetching the data back into Dart works for most important data types.

All database operations are sync 😃.

There are several features that are not yet implemented. For example:

  • Inserting data into DuckDb is usually done with an appender. Right now, the recommended way to insert bulk data is to use the native DuckDb functionality read_csv, read_parquet, read_json_auto, see documentation.

  • Complex data types (list, struct, array)

Because DuckDb also has a WASM implementation, it should be possible to run/embed it into Flutter and on the Web. I have not explored that direction.

Disclaimer #

As I am not an expert in databases, C, or even Dart, there should be significant room for improvement in the performance and ergonomics of this package. PR's are welcome. I may not be able to engage in the long term maintenance of this package, and it's very likely that I won't provide the level of support the community needs. If the development of this package is not happening fast enough for you, consider becoming a contributor so you can take this project further and faster. I created this package because DuckDB was worth exploring and there are not a lot of DB offerings for Dart on the backend.

A huge thanks to the Dart FFI package designers. The FFI gen just works! It's amazing.

Getting started #

I only have access to an Ubuntu 22.04 and a Windows 10 machine for testing. The package has been tested with the 1.1.0 DuckDb version.

To use the package, you need to install the Command line and the C/C++ bindings on your machine, see installation.
It is painless process. For Linux systems, just copy the libduckdb.so in the /usr/local/lib folder. For Window, make sure the dll is on your path.

Usage #

final con = Connection.inMemory();
con.execute('CREATE TABLE tbl (state VARCHAR, population INTEGER);');
con.execute("INSERT INTO tbl VALUES ('CA', 39539223), ('VA', 8631393);");
var result = con.fetch('SELECT * FROM tbl;');
con.close();  // close the connection to release resources

You can also load an existing database from disk

final con = Connection('data.duckdb');
final res = con.fetch('SHOW TABLES;');
con.close();

Or read in a csv file directly

final con = Connection.inMemory();
con.execute("CREATE TABLE ontime AS SELECT * FROM 'flights.csv'");
con.fetch('SELECT * FROM ontime LIMIT 5;');

See the test/duckdb_test.dart for more examples.

Map query result to a Dart class #

For convenience, you can map a row of the resulting query directly to a Dart class using fetchRows. For example, given the table

con.execute('CREATE TABLE people (name VARCHAR, age INTEGER);');
con.execute("INSERT INTO people VALUES ('Tom', 31), ('Jenny', 29), ('Maria', 33);");

and the class

final class Person {
  Person({required this.name, required this.age});
  String name;
  int age;
}

you can map the rows of the table to a Person using fetchRows

final result = con.fetchRows('SELECT name, age FROM people ORDER BY name;',
    (List row) => Person(name: row[0], age: row[1]));
assert(result.length == 3);
assert(result.first.name == 'Jenny');
assert(result.first.age == 29);

Additional information #

The documentation on the DuckDb web site is comprehensive. For more info on Db internals, see the presentation.

Info for authors #

The Dart client is based on the DuckDb C API. The DuckDb tests for the C API are located at https://github.com/duckdb/duckdb/blob/main/test/api/capi

Download the C/C++ DuckDb bindings and extract the zip file.

  • Put the duckdb.h header file in the ./third_party folder
  • Copy the libduckdb.so in the /usr/local/lib folder
  • Run dart run ffigen --config ffigen.yaml to generate the bindings.
    Bindings get generated in file ./src/ffi/duckdb.g.dart