// // DuckDB // https://github.com/duckdb/duckdb-swift // // Copyright © 2018-2024 Stichting DuckDB Foundation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. @_implementationOnly import Cduckdb import Foundation /// A DuckDB result set column /// /// DuckDB columns represent a vertical slice of a result set table. All DuckDB /// columns have an underlying database type (accessed via the /// ``underlyingDatabaseType`` member) which determine the native Swift types to /// which the column can be cast to. /// /// When columns are initially retrieved from a ``ResultSet`` through its /// ``ResultSet/subscript(_:)`` accessor they have an element type of `Void`. /// Only after a column is cast to a matching native type can its elements be /// accessed. /// /// For example, a column with an underlying database type of /// ``DatabaseType/varchar`` can be cast to type `String`: /// /// ```swift /// // casts the first column in a result set to string /// let column = result[0].cast(to: String.self) /// ``` /// /// The documentation for each ``DatabaseType`` member specifies which native /// Swift types a column may be cast to. /// /// As a column is a Swift `Collection` type, once a column has been /// successfully cast its elements can be accessed in the same way as any other /// Swift collection type. /// /// ```swift /// for element in column { /// print("element: \(element)") /// } /// ``` public struct Column { private let result: ResultSet private let columnIndex: DBInt private let unwrap: @Sendable (Vector.Element) throws -> DataType? init( result: ResultSet, columnIndex: DBInt, unwrap: @escaping @Sendable (Vector.Element) throws -> DataType? ) { self.result = result self.columnIndex = columnIndex self.unwrap = unwrap } /// The name of the table column public var name: String { result.columnName(at: columnIndex) } /// The native Swift type to which the column has been cast public var dataType: DataType.Type { DataType.self } /// The underlying primitive database type of the column public var underlyingDatabaseType: DatabaseType { result.columnDataType(at: columnIndex) } /// The underlying logical type of the column public var underlyingLogicalType: LogicalType { result.columnLogicalType(at: columnIndex) } } // MARK: - Type Casting public extension Column { /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Void.Type) -> Column { .init(result: result, columnIndex: columnIndex) { $0.unwrapNull() ? nil : () } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Bool.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(Bool.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Warning: Implicit conversion of a DuckDB integer column value greater /// than `Int.max` or less than `Int.min` is a programmer error and will /// result in a runtime precondition failure /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Int.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(Int.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Int8.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(Int8.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Int16.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(Int16.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Int32.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(Int32.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Int64.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(Int64.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: IntHuge.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(IntHuge.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: UIntHuge.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(UIntHuge.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Warning: Implicit conversion of a DuckDB integer column value greater /// than `UInt.max` is a programmer error and will result in a runtime /// precondition failure /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: UInt.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(UInt.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: UInt8.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(UInt8.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: UInt16.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(UInt16.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: UInt32.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(UInt32.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: UInt64.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(UInt64.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Float.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(Float.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Double.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(Double.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: String.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(String.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: UUID.Type) -> Column { .init(result: result, columnIndex: columnIndex) { try $0.unwrap(UUID.self) } } /// Casts the column to the given type /// /// A column cast always succeeds but if there is a type-mismatch between /// the given type and the column's underlying database type, returned /// elements will always be equal to `nil`. /// /// - Parameter type: the native Swift type to cast to /// - Returns: a typed DuckDB result set ``Column`` func cast(to type: Time.Type) -> Column