109 lines
3.6 KiB
Swift
109 lines
3.6 KiB
Swift
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
|
||
/// function’s 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 function’s 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)
|
||
}
|
||
}
|