const std = @import("std"); const c = @cImport({ @cInclude("duckdb.h"); }); const DuckdbType = enum { BOOLEAN, TINYINT, SMALLINT, INTEGER, BIGINT, UTINYINT, USMALLINT, UINTEGER, UBIGINT, FLOAT, DOUBLE, TIMESTAMP, DATE, TIME, INTERVAL, HUGEINT, UHUGEINT, VARCHAR, BLOB, TIMESTAMP_S, TIMESTAMP_MS, TIMESTAMP_NS, UUID, TIME_TZ, TIMESTAMP_TZ, }; pub const Column = union(DuckdbType) { BOOLEAN: [*]bool, TINYINT: [*]i8, SMALLINT: [*]i16, INTEGER: [*]i32, BIGINT: [*]i64, UTINYINT: [*]u8, USMALLINT: [*]u16, UINTEGER: [*]u32, UBIGINT: [*]u64, FLOAT: [*]f32, DOUBLE: [*]f64, TIMESTAMP: [*]c.duckdb_timestamp, DATE: [*]c.duckdb_date, TIME: [*]c.duckdb_time, INTERVAL: [*]c.duckdb_interval, HUGEINT: [*]c.duckdb_hugeint, UHUGEINT: [*]c.duckdb_uhugeint, VARCHAR: [*]c.duckdb_string_t, BLOB: [*]c.duckdb_string_t, TIMESTAMP_S: [*]c.duckdb_timestamp, TIMESTAMP_MS: [*]c.duckdb_timestamp, TIMESTAMP_NS: [*]c.duckdb_timestamp, UUID: [*]c.duckdb_hugeint, TIME_TZ: [*]c.duckdb_time_tz, TIMESTAMP_TZ: [*]c.duckdb_timestamp, const Self = @This(); pub fn fromType(column_type: c.DUCKDB_TYPE, column: *anyopaque) Column { return switch (column_type) { c.DUCKDB_TYPE_BOOLEAN => .{.BOOLEAN = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_TINYINT => .{.TINYINT = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_SMALLINT => .{.SMALLINT = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_INTEGER => .{.INTEGER = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_BIGINT => .{.BIGINT = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_UTINYINT => .{.UTINYINT = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_USMALLINT => .{.USMALLINT = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_UINTEGER => .{.UINTEGER = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_UBIGINT => .{.UBIGINT = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_FLOAT => .{.FLOAT = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_DOUBLE => .{.DOUBLE = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_VARCHAR => .{.VARCHAR = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_BLOB => .{.BLOB = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_TIMESTAMP => .{.TIMESTAMP = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_DATE => .{.DATE = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_TIME => .{.TIME = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_INTERVAL => .{.INTERVAL = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_HUGEINT => .{.HUGEINT = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_UHUGEINT => .{.UHUGEINT = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_TIMESTAMP_S => .{.TIMESTAMP_S = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_TIMESTAMP_MS => .{.TIMESTAMP_MS = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_TIMESTAMP_NS => .{.TIMESTAMP_NS = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_UUID => .{.UUID = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_TIME_TZ => .{.TIME_TZ = @alignCast(@ptrCast(column))}, c.DUCKDB_TYPE_TIMESTAMP_TZ => .{.TIMESTAMP_TZ = @alignCast(@ptrCast(column))}, else => unreachable, }; } pub fn getAs(self: Self, i: usize, T: anytype) !T{ const ti : std.builtin.Type = @typeInfo(T); switch (self){ .BOOLEAN => |ptr| switch(ti) { .Bool => return ptr[i], .Int => return @intFromBool(ptr[i]), else => return error.InvalidConversion, }, .TINYINT => |ptr| switch(ti) { .Int => return @intCast(ptr[i]), .Float => return @floatFromInt(ptr[i]), else => return error.InvalidConversion, }, .SMALLINT => |ptr| switch(ti) { .Int => return @intCast(ptr[i]), .Float => return @floatFromInt(ptr[i]), else => return error.InvalidConversion, }, .INTEGER => |ptr| switch(ti) { .Int => return @intCast(ptr[i]), .Float => return @floatFromInt(ptr[i]), else => return error.InvalidConversion, }, .BIGINT => |ptr| switch(ti) { .Int => return @intCast(ptr[i]), .Float => return @floatFromInt(ptr[i]), else => return error.InvalidConversion, }, .UTINYINT => |ptr| switch(ti) { .Int => return @intCast(ptr[i]), .Float => return @floatFromInt(ptr[i]), else => return error.InvalidConversion, }, .USMALLINT => |ptr| switch(ti) { .Int => return @intCast(ptr[i]), .Float => return @floatFromInt(ptr[i]), else => return error.InvalidConversion, }, .UINTEGER => |ptr| switch(ti) { .Int => return @intCast(ptr[i]), .Float => return @floatFromInt(ptr[i]), else => return error.InvalidConversion, }, .UBIGINT => |ptr| switch(ti) { .Int => return @intCast(ptr[i]), .Float => return @floatFromInt(ptr[i]), else => return error.InvalidConversion, }, .FLOAT => |ptr| switch(ti) { .Int => return @intFromFloat(ptr[i]), .Float => return @floatCast(ptr[i]), else => return error.InvalidConversion, }, .DOUBLE => |ptr| switch(ti) { .Int => return @intFromFloat(ptr[i]), .Float => return @floatCast(ptr[i]), else => return error.InvalidConversion, }, .VARCHAR, .BLOB => |ptr| switch(ti){ .Pointer => |p| switch (p.size) { .Slice => { if ( p.child == u8 ) { var result: T = undefined; if (c.duckdb_string_is_inlined(ptr[i])){ result = &ptr[i].value.inlined.inlined; result.len = ptr[i].value.inlined.length; return result; } else { result.len = ptr[i].value.pointer.length; result.ptr = ptr[i].value.pointer.ptr; return result; } } else { @compileError("Invalid type for output data: " ++ @typeName(T)); } }, else => return error.InvalidConversion, }, else => return error.InvalidConversion, }, .TIMESTAMP, .DATE, .TIME, .INTERVAL, .HUGEINT, .UHUGEINT, .TIMESTAMP_S, .TIMESTAMP_MS, .TIMESTAMP_NS, .UUID, .TIME_TZ, .TIMESTAMP_TZ => return error.ConversionNotImplemented, } } };