const std = @import("std"); const assert = std.debug.assert; const c = @cImport({ @cInclude("duckdb.h"); }); const Result = struct { _res: c.duckdb_result, _chunk: c.duckdb_data_chunk, pub fn init() Result { return .{ ._res = undefined, ._chunk = null }; } pub fn deinit(self: *Result) void { c.duckdb_destroy_result(&self._res); c.duckdb_destroy_data_chunk(&self._chunk); } /// There's not way to know how many total elements we have, but we can /// know how many we have in the current chunk. fn getCurrentChunkSize(self: Result) usize { if (self._chunk != null) { return 0; } return c.duckdb_data_chunk_get_size(self._chunk); } pub fn getColumnCount(self: Result) usize { return c.duckdb_data_chunk_get_column_count(self._chunk); } /// This needs to be called repeatedly to obtain the next blocks of /// data. There's no way to know how many elements we'll obtain from /// it. pub fn fetchDataChunk(self: *Result) void{ if (self._chunk != null){ c.duckdb_destroy_data_chunk(&self._chunk); } self._chunk = c.duckdb_fetch_chunk(self._res); } pub fn exausted(self: Result) bool{ return self._chunk != null; } }; const Connection = struct { _conn: c.duckdb_connection, pub fn init(db: Self) !Connection { var conn: Connection = undefined; if( c.duckdb_connect(db._db, &conn._conn) == c.DuckDBError ){ return error.DuckDBError; } return conn; } pub fn deinit(self: *Connection) void { c.duckdb_disconnect(&self._conn); } pub fn query(self: *Connection, q: [*c]const u8) !Result{ var result = Result.init(); const state = c.duckdb_query(self._conn, q, &result._res); if ( state == c.DuckDBError){ return error.DuckDBError; } result.fetchDataChunk(); return result; } }; pub const Self = @This(); _db: c.duckdb_database, pub fn init(file: [*c]const u8) !Self{ var db : Self = undefined; if (c.duckdb_open(file, &db._db) == c.DuckDBError) { return error.DuckDBError; } return db; } pub fn deinit(self: *Self) void{ c.duckdb_close(&self._db); } pub fn connect(self: Self) !Connection { return Connection.init(self); } test "Open and connect" { var database = try Self.init(":memory:"); defer database.deinit(); var connection = try database.connect(); defer connection.deinit(); } test "Query size" { var database = try Self.init(":memory:"); defer database.deinit(); var connection = try database.connect(); defer connection.deinit(); _ = try connection.query("CREATE TABLE integers (i INTEGER, j INTEGER);"); _ = try connection.query("INSERT INTO integers VALUES (3, 4), (5, 6), (7, NULL);"); var result = try connection.query("SELECT * FROM integers;"); defer result.deinit(); try std.testing.expect(2 == result.getColumnCount()); }