DataLiteCore swift package

This commit is contained in:
2025-04-24 23:48:46 +03:00
parent b0e52a72b7
commit 6f955b2c43
70 changed files with 7939 additions and 1 deletions

View File

@@ -0,0 +1,168 @@
import Foundation
import DataLiteC
/// A base class representing a custom SQLite function.
///
/// This class provides a framework for defining custom functions in SQLite. Subclasses must
/// override specific properties and methods to define the function's behavior, including
/// its name, argument count, and options.
///
/// To create a custom SQLite function, you should subclass either ``Scalar`` or
/// ``Aggregate`` depending on whether your function is a scalar function (returns
/// a single result) or an aggregate function (returns a result accumulated from multiple
/// rows). The subclass will then override the necessary properties and methods to implement
/// the function's behavior.
///
/// ## Topics
///
/// ### Base Function Classes
///
/// - ``Aggregate``
/// - ``Scalar``
///
/// ### Custom Function Classes
///
/// - ``Regexp``
open class Function {
// MARK: - Properties
/// The number of arguments that the custom SQLite function accepts.
///
/// This property must be overridden by subclasses to specify how many arguments
/// the function expects. The value should be a positive integer representing the
/// number of arguments, or zero if the function does not accept arguments.
open class var argc: Int32 {
fatalError("Subclasses must override this property to specify the number of arguments.")
}
/// The name of the custom SQLite function.
///
/// This property must be overridden by subclasses to provide the name that the SQLite
/// engine will use to identify the function. The name should be a valid SQLite function
/// name according to SQLite naming conventions.
open class var name: String {
fatalError("Subclasses must override this property to provide the function name.")
}
/// The options for the custom SQLite function.
///
/// This property must be overridden by subclasses to specify options such as whether the
/// function is deterministic or not. Options are represented as a bitmask of `Function.Options`.
open class var options: Options {
fatalError("Subclasses must override this property to specify function options.")
}
/// The encoding used by the function, which defaults to UTF-8.
///
/// This is used to set the encoding for text data in the custom SQLite function. The default
/// encoding is UTF-8, but this can be modified if necessary. This encoding is combined with
/// the function's options to configure the function.
class var encoding: Function.Options {
Function.Options(rawValue: SQLITE_UTF8)
}
/// The combined options for the custom SQLite function.
///
/// This property combines the function's options with the encoding. The result is used when
/// registering the function with SQLite. This property is derived from `options` and `encoding`.
class var opts: Int32 {
var options = options
options.insert(encoding)
return options.rawValue
}
// MARK: - Methods
/// Installs the custom SQLite function into the specified database connection.
///
/// Subclasses must override this method to provide the implementation for installing
/// the function into the SQLite database. This typically involves registering the function
/// with SQLite using `sqlite3_create_function_v2` or similar APIs.
///
/// - Parameter connection: A pointer to the SQLite database connection where the function
/// will be installed.
/// - Throws: An error if the function installation fails. The method will throw an exception
/// if the installation cannot be completed successfully.
class func install(db connection: OpaquePointer) throws(Connection.Error) {
fatalError("Subclasses must override this method to implement function installation.")
}
/// Uninstalls the custom SQLite function from the specified database connection.
///
/// This method unregisters the function from the SQLite database using `sqlite3_create_function_v2`
/// with `NULL` for the function implementations. This effectively removes the function from the
/// database.
///
/// - Parameter connection: A pointer to the SQLite database connection from which the function
/// will be uninstalled.
/// - Throws: An error if the function uninstallation fails. An exception is thrown if the function
/// cannot be removed successfully.
class func uninstall(db connection: OpaquePointer) throws(Connection.Error) {
let status = sqlite3_create_function_v2(
connection,
name, argc, opts,
nil, nil, nil, nil, nil
)
if status != SQLITE_OK {
throw Connection.Error(connection)
}
}
}
// MARK: - Functions
/// Sets the result of an SQLite query as a text string.
///
/// This function sets the result of the query to the specified text string. SQLite will store
/// this string inside the database as the result of the custom function.
///
/// - Parameters:
/// - ctx: A pointer to the SQLite context that provides information about the current query.
/// - string: A `String` that will be returned as the result of the query.
///
/// - Note: The `SQLITE_TRANSIENT` flag is used, meaning that SQLite makes a copy of the passed
/// data. This ensures that the string remains valid after the function execution is completed.
func sqlite3_result_text(_ ctx: OpaquePointer!, _ string: String) {
sqlite3_result_text(ctx, string, -1, SQLITE_TRANSIENT)
}
/// Sets the result of an SQLite query as binary data (BLOB).
///
/// This function sets the result of the query to the specified binary data. This is useful for
/// returning non-textual data such as images or other binary content from a custom function.
///
/// - Parameters:
/// - ctx: A pointer to the SQLite context that provides information about the current query.
/// - data: A `Data` object representing the binary data to be returned as the result.
///
/// - Note: The `SQLITE_TRANSIENT` flag is used, ensuring that SQLite makes a copy of the binary
/// data. This prevents issues related to memory management if the original data is modified
/// or deallocated after the function completes.
func sqlite3_result_blob(_ ctx: OpaquePointer!, _ data: Data) {
data.withUnsafeBytes {
sqlite3_result_blob(ctx, $0.baseAddress, Int32($0.count), SQLITE_TRANSIENT)
}
}
/// Sets the result of an SQLite query based on the `SQLiteRawValue` type.
///
/// This function sets the result of the query according to the type of the provided value. It can
/// handle integers, floating-point numbers, strings, binary data, or `NULL` values.
///
/// - Parameters:
/// - ctx: A pointer to the SQLite context that provides information about the current query.
/// - value: A `SQLiteRawValue` that represents the result to be returned. If the value is `nil`,
/// the result will be set to `NULL`.
///
/// - Note: The function uses a `switch` statement to determine the type of the value and then
/// calls the appropriate SQLite function to set the result. This ensures that the correct SQLite
/// result type is used based on the provided value.
func sqlite3_result_value(_ ctx: OpaquePointer!, _ value: SQLiteRawValue?) {
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)
}
}