Files
data-lite-core/Sources/DataLiteCore/Classes/Function.swift

109 lines
3.6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
import DataLiteC
/// A base class representing a user-defined SQLite function.
///
/// The `Function` class defines the common interface and structure for implementing custom SQLite
/// functions. Subclasses are responsible for specifying the function name, argument count, and
/// behavior. This class should not be used directly instead, use one of its specialized
/// subclasses, such as ``Scalar`` or ``Aggregate``.
///
/// To define a new SQLite function, subclass either ``Scalar`` or ``Aggregate`` depending on
/// whether the function computes a value from a single row or aggregates results across multiple
/// rows. Override the required properties and implement the necessary logic to define the
/// functions behavior.
///
/// ## Topics
///
/// ### Base Function Classes
///
/// - ``Scalar``
/// - ``Aggregate``
///
/// ### Custom Function Classes
///
/// - ``Regexp``
///
/// ### Configuration
///
/// - ``argc``
/// - ``name``
/// - ``options``
/// - ``Options``
open class Function {
// MARK: - Properties
/// The number of arguments that the function accepts.
///
/// Subclasses must override this property to specify the expected number of arguments. The
/// value should be a positive integer, or zero if the function does not accept any arguments.
open class var argc: Int32 {
fatalError("Subclasses must override this property to specify the number of arguments.")
}
/// The name of the function.
///
/// Subclasses must override this property to provide the name by which the SQLite engine
/// identifies the function. The name must comply with SQLite function naming rules.
open class var name: String {
fatalError("Subclasses must override this property to provide the function name.")
}
/// The configuration options for the function.
///
/// Subclasses must override this property to specify the functions behavioral flags, such as
/// whether it is deterministic, direct-only, or innocuous.
open class var options: Options {
fatalError("Subclasses must override this property to specify function options.")
}
class var encoding: Function.Options {
Function.Options(rawValue: SQLITE_UTF8)
}
class var opts: Int32 {
var options = options
options.insert(encoding)
return options.rawValue
}
// MARK: - Methods
class func install(db connection: OpaquePointer) throws(SQLiteError) {
fatalError("Subclasses must override this method to implement function installation.")
}
class func uninstall(db connection: OpaquePointer) throws(SQLiteError) {
let status = sqlite3_create_function_v2(
connection,
name, argc, opts,
nil, nil, nil, nil, nil
)
if status != SQLITE_OK {
throw SQLiteError(connection)
}
}
}
// MARK: - Functions
func sqlite3_result_text(_ ctx: OpaquePointer!, _ string: String) {
sqlite3_result_text(ctx, string, -1, SQLITE_TRANSIENT)
}
func sqlite3_result_blob(_ ctx: OpaquePointer!, _ data: Data) {
data.withUnsafeBytes {
sqlite3_result_blob(ctx, $0.baseAddress, Int32($0.count), SQLITE_TRANSIENT)
}
}
func sqlite3_result_value(_ ctx: OpaquePointer!, _ value: SQLiteValue?) {
switch value ?? .null {
case .int(let value): sqlite3_result_int64(ctx, value)
case .real(let value): sqlite3_result_double(ctx, value)
case .text(let value): sqlite3_result_text(ctx, value)
case .blob(let value): sqlite3_result_blob(ctx, value)
case .null: sqlite3_result_null(ctx)
}
}