Refactor entire codebase and rewrite documentation

This commit is contained in:
2025-10-10 18:06:34 +03:00
parent b4e9755c15
commit 8e471f2b9f
74 changed files with 3405 additions and 4149 deletions

View File

@@ -2,33 +2,36 @@ import Foundation
/// Represents the journal modes available for an SQLite database.
///
/// The journal mode determines how the database handles transactions and how it
/// maintains the journal for rollback and recovery. For more details, refer to
/// [Journal Mode Pragma](https://www.sqlite.org/pragma.html#pragma_journal_mode).
public enum JournalMode: String, SQLiteRawRepresentable {
/// The journal mode determines how the database handles transactions and how it maintains the
/// journal for rollback and recovery.
///
/// - SeeAlso: [journal_mode](https://sqlite.org/pragma.html#pragma_journal_mode)
public enum JournalMode: String, SQLiteRepresentable {
/// DELETE journal mode.
///
/// This is the default behavior. The rollback journal is deleted at the conclusion
/// of each transaction. The delete operation itself causes the transaction to commit.
/// For more details, refer to the
/// [Atomic Commit In SQLite](https://www.sqlite.org/atomiccommit.html).
/// This is the default behavior. The rollback journal is deleted at the conclusion of each
/// transaction. The delete operation itself causes the transaction to commit.
///
/// - SeeAlso: [Atomic Commit In SQLite](https://sqlite.org/atomiccommit.html)
case delete
/// TRUNCATE journal mode.
///
/// In this mode, the rollback journal is truncated to zero length at the end of each transaction
/// instead of being deleted. On many systems, truncating a file is much faster than deleting it
/// because truncating does not require modifying the containing directory.
/// In this mode, the rollback journal is truncated to zero length at the end of each
/// transaction instead of being deleted. On many systems, truncating a file is much faster than
/// deleting it because truncating does not require modifying the containing directory.
case truncate
/// PERSIST journal mode.
///
/// In this mode, the rollback journal is not deleted at the end of each transaction. Instead,
/// the header of the journal is overwritten with zeros. This prevents other database connections
/// from rolling the journal back. The PERSIST mode is useful as an optimization on platforms
/// where deleting or truncating a file is more expensive than overwriting the first block of a file
/// with zeros. For additional configuration, refer to
/// [journal_size_limit](https://www.sqlite.org/pragma.html#pragma_journal_size_limit).
/// the header of the journal is overwritten with zeros. This prevents other database
/// connections from rolling the journal back. The PERSIST mode is useful as an optimization on
/// platforms where deleting or truncating a file is more expensive than overwriting the first
/// block of a file with zeros.
///
/// - SeeAlso: [journal_size_limit](
/// https://sqlite.org/pragma.html#pragma_journal_size_limit)
case persist
/// MEMORY journal mode.
@@ -42,41 +45,63 @@ public enum JournalMode: String, SQLiteRawRepresentable {
///
/// This mode uses a write-ahead log instead of a rollback journal to implement transactions.
/// The WAL mode is persistent, meaning it stays in effect across multiple database connections
/// and persists even after closing and reopening the database. For more details, refer to the
/// [Write-Ahead Logging](https://www.sqlite.org/wal.html).
/// and persists even after closing and reopening the database.
///
/// - SeeAlso: [Write-Ahead Logging](https://sqlite.org/wal.html)
case wal
/// OFF journal mode.
///
/// In this mode, the rollback journal is completely disabled, meaning no rollback journal is ever created.
/// This disables SQLite's atomic commit and rollback capabilities. The `ROLLBACK` command will no longer work
/// and behaves in an undefined way. Applications must avoid using the `ROLLBACK` command when the journal mode is OFF.
/// If the application crashes in the middle of a transaction, the database file will likely become corrupt,
/// as there is no way to unwind partially completed operations. For example, if a duplicate entry causes a
/// `CREATE UNIQUE INDEX` statement to fail halfway through, it will leave behind a partially created index,
/// resulting in a corrupted database state.
/// In this mode, the rollback journal is completely disabled, meaning no rollback journal is
/// ever created. This disables SQLite's atomic commit and rollback capabilities. The `ROLLBACK`
/// command will no longer work and behaves in an undefined way. Applications must avoid using
/// the `ROLLBACK` command when the journal mode is OFF. If the application crashes in the
/// middle of a transaction, the database file will likely become corrupt, as there is no way to
/// unwind partially completed operations. For example, if a duplicate entry causes a
/// `CREATE UNIQUE INDEX` statement to fail halfway through, it will leave behind a partially
/// created index, resulting in a corrupted database state.
case off
/// The string representation of the journal mode recognized by SQLite.
///
/// Each case maps to its corresponding uppercase string value expected by SQLite. For example,
/// `.wal` maps to `"WAL"`. This value is typically used when reading or setting the journal mode
/// through the `PRAGMA journal_mode` command.
///
/// - Returns: The uppercase string identifier of the journal mode as understood by SQLite.
///
/// - SeeAlso: [journal_mode](https://sqlite.org/pragma.html#pragma_journal_mode)
public var rawValue: String {
switch self {
case .delete: "DELETE"
case .truncate: "TRUNCATE"
case .persist: "PERSIST"
case .memory: "MEMORY"
case .wal: "WAL"
case .off: "OFF"
case .delete: "DELETE"
case .truncate: "TRUNCATE"
case .persist: "PERSIST"
case .memory: "MEMORY"
case .wal: "WAL"
case .off: "OFF"
}
}
/// Creates a `JournalMode` instance from a string representation.
///
/// The initializer performs a case-insensitive match between the provided string and the known
/// SQLite journal mode names. If the input does not correspond to any valid journal mode, the
/// initializer returns `nil`.
///
/// - Parameter rawValue: The string name of the journal mode, as defined by SQLite.
/// - Returns: A `JournalMode` value if the input string matches a supported mode; otherwise,
/// `nil`.
///
/// - SeeAlso: [journal_mode](https://sqlite.org/pragma.html#pragma_journal_mode)
public init?(rawValue: String) {
switch rawValue.uppercased() {
case "DELETE": self = .delete
case "TRUNCATE": self = .truncate
case "PERSIST": self = .persist
case "MEMORY": self = .memory
case "WAL": self = .wal
case "OFF": self = .off
default: return nil
case "DELETE": self = .delete
case "TRUNCATE": self = .truncate
case "PERSIST": self = .persist
case "MEMORY": self = .memory
case "WAL": self = .wal
case "OFF": self = .off
default: return nil
}
}
}

View File

@@ -1,40 +1,34 @@
import Foundation
/// Represents different types of database update actions.
/// Represents a type of database change operation.
///
/// The `SQLiteAction` enum is used to identify the type of action
/// performed on a database, such as insertion, updating, or deletion.
/// The `SQLiteAction` enumeration describes an action that modifies a database table. It
/// distinguishes between row insertions, updates, and deletions, providing context such
/// as the database name, table, and affected row ID.
///
/// - SeeAlso: [Data Change Notification Callbacks](https://sqlite.org/c3ref/update_hook.html)
public enum SQLiteAction {
/// Indicates the insertion of a new row into a table.
///
/// This case is used to represent the action of adding a new
/// row to a specific table in a database.
/// A new row was inserted into a table.
///
/// - Parameters:
/// - db: The name of the database where the insertion occurred.
/// - table: The name of the table where the insertion occurred.
/// - rowID: The row ID of the newly inserted row.
/// - db: The name of the database where the insertion occurred.
/// - table: The name of the table into which the row was inserted.
/// - rowID: The row ID of the newly inserted row.
case insert(db: String, table: String, rowID: Int64)
/// Indicates the modification of an existing row in a table.
///
/// This case is used to represent the action of updating an
/// existing row within a specific table in a database.
/// An existing row was modified in a table.
///
/// - Parameters:
/// - db: The name of the database where the update occurred.
/// - table: The name of the table where the update occurred.
/// - rowID: The row ID of the updated row.
/// - db: The name of the database where the update occurred.
/// - table: The name of the table containing the updated row.
/// - rowID: The row ID of the modified row.
case update(db: String, table: String, rowID: Int64)
/// Indicates the removal of a row from a table.
///
/// This case is used to represent the action of deleting a
/// row from a specific table in a database.
/// A row was deleted from a table.
///
/// - Parameters:
/// - db: The name of the database from which the row was deleted.
/// - table: The name of the table from which the row was deleted.
/// - rowID: The row ID of the deleted row.
/// - db: The name of the database where the deletion occurred.
/// - table: The name of the table from which the row was deleted.
/// - rowID: The row ID of the deleted row.
case delete(db: String, table: String, rowID: Int64)
}

View File

@@ -1,75 +0,0 @@
import Foundation
import DataLiteC
/// Represents different types of columns in an SQLite database.
///
/// The `SQLiteRawType` enum encapsulates the various data types that SQLite supports for columns.
/// Each case in the enum corresponds to a specific SQLite data type, providing a way to work with these
/// types in a type-safe manner. This enum allows for easier handling of SQLite column types by abstracting
/// their raw representations and offering more readable code.
/// For more details, refer to [Datatypes In SQLite](https://www.sqlite.org/datatype3.html).
///
/// ## Topics
///
/// ### Enumeration Cases
///
/// - ``int``
/// - ``real``
/// - ``text``
/// - ``blob``
/// - ``null``
///
/// ### Instance Properties
///
/// - ``rawValue``
///
/// ### Initializers
///
/// - ``init(rawValue:)``
public enum SQLiteRawType: Int32 {
/// The data type of an integer column.
case int
/// The data type of a real (floating point) column.
case real
/// The data type of a text (string) column.
case text
/// The data type of a blob (binary large object) column.
case blob
/// The data type of a NULL column.
case null
/// Returns the raw SQLite data type value corresponding to the column type.
///
/// This computed property provides the raw integer value used by SQLite to represent each column type.
///
/// - Returns: An `Int32` representing the SQLite data type constant.
public var rawValue: Int32 {
switch self {
case .int: return SQLITE_INTEGER
case .real: return SQLITE_FLOAT
case .text: return SQLITE_TEXT
case .blob: return SQLITE_BLOB
case .null: return SQLITE_NULL
}
}
/// Initializes a `SQLiteRawType` enum case from its raw value.
///
/// This initializer maps a raw `Int32` value (SQLite constant) to the corresponding enum case.
///
/// - Parameter rawValue: The raw value representing the column type as defined by SQLite.
public init?(rawValue: Int32) {
switch rawValue {
case SQLITE_INTEGER: self = .int
case SQLITE_FLOAT: self = .real
case SQLITE_TEXT: self = .text
case SQLITE_BLOB: self = .blob
case SQLITE_NULL: self = .null
default: return nil
}
}
}

View File

@@ -1,99 +0,0 @@
import Foundation
/// An enumeration that represents the different types of raw values in an SQLite database.
///
/// This type is used to store values retrieved from or stored in an SQLite database. It supports
/// various data types such as integers, floating-point numbers, text, binary data, and null values.
/// For more details, refer to [Datatypes In SQLite](https://www.sqlite.org/datatype3.html).
///
/// ## Example
///
/// ```swift
/// let integerValue: SQLiteRawValue = .int(42)
/// let realValue: SQLiteRawValue = .real(3.14)
/// let textValue: SQLiteRawValue = .text("Hello, SQLite")
/// let blobValue: SQLiteRawValue = .blob(Data([0x01, 0x02, 0x03]))
/// let nullValue: SQLiteRawValue = .null
/// ```
///
/// ## Topics
///
/// ### Enumeration Cases
///
/// - ``int(_:)``
/// - ``real(_:)``
/// - ``text(_:)``
/// - ``blob(_:)``
/// - ``null``
public enum SQLiteRawValue: Equatable {
/// Represents a 64-bit integer value.
case int(Int64)
/// Represents a floating-point number.
case real(Double)
/// Represents a text string.
case text(String)
/// Represents binary large objects (BLOBs).
case blob(Data)
/// Represents a SQL `NULL` value.
case null
}
extension SQLiteRawValue: SQLiteLiteralable {
/// Returns a string representation of the value suitable for use in SQL queries.
///
/// This method converts the `SQLiteRawValue` into a format that is directly usable in SQL statements:
/// - For `.int`: Converts the integer to its string representation.
/// - For `.real`: Converts the floating-point number to its string representation.
/// - For `.text`: Escapes single quotes within the string and wraps the result in single quotes.
/// - For `.blob`: Converts the binary data to a hexadecimal string representation, formatted as `X'...'`.
/// - For `.null`: Returns the SQL literal `"NULL"`.
///
/// The resulting string is formatted for inclusion in SQL queries, ensuring proper handling of the value
/// according to SQL syntax.
///
/// - Returns: A string representation of the value, formatted for use in SQL queries.
public var sqliteLiteral: String {
switch self {
case .int(let int): return "\(int)"
case .real(let real): return "\(real)"
case .text(let text): return "'\(text.replacingOccurrences(of: "'", with: "''"))'"
case .blob(let data): return "X'\(data.hex)'"
case .null: return "NULL"
}
}
}
extension SQLiteRawValue: CustomStringConvertible {
/// A textual representation of the `SQLiteRawValue`.
///
/// This property returns the string representation of the `SQLiteRawValue` as defined by the `sqliteLiteral` method.
/// It provides a clear and readable format of the value, useful for debugging and logging purposes.
///
/// - Returns: A string that represents the `SQLiteRawValue` in a format suitable for display.
public var description: String {
return sqliteLiteral
}
}
extension Data {
/// Converts the data to a hexadecimal string representation.
///
/// This method converts each byte of the `Data` instance into its two-digit hexadecimal representation.
/// The hexadecimal values are concatenated into a single string. This is useful for representing binary data
/// in a human-readable format, particularly for SQL BLOB literals.
///
/// ## Example
/// ```swift
/// let data = Data([0x01, 0x02, 0x03])
/// print(data.hex) // Output: "010203"
/// ```
///
/// - Returns: A hexadecimal string representation of the data.
var hex: String {
return map { String(format: "%02hhX", $0) }.joined()
}
}

View File

@@ -0,0 +1,65 @@
import Foundation
/// An enumeration that represents raw SQLite values.
///
/// `SQLiteValue` encapsulates all fundamental SQLite storage classes. It is used to
/// store values retrieved from or written to a SQLite database, providing a type-safe
/// Swift representation for each supported data type.
///
/// - SeeAlso: [Datatypes In SQLite](https://sqlite.org/datatype3.html)
///
/// ## Topics
///
/// ### Enumeration Cases
///
/// - ``int(_:)``
/// - ``real(_:)``
/// - ``text(_:)``
/// - ``blob(_:)``
/// - ``null``
public enum SQLiteValue: Equatable, Hashable, Sendable {
/// A 64-bit integer value.
case int(Int64)
/// A double-precision floating-point value.
case real(Double)
/// A text string encoded in UTF-8.
case text(String)
/// Binary data (BLOB).
case blob(Data)
/// A `NULL` value.
case null
}
public extension SQLiteValue {
/// A SQL literal representation of the value.
///
/// Converts the current value into a string suitable for embedding directly in an SQL
/// statement. Strings are quoted and escaped, binary data is encoded in hexadecimal form, and
/// `NULL` is represented by the literal `NULL`.
var sqliteLiteral: String {
switch self {
case .int(let int): "\(int)"
case .real(let real): "\(real)"
case .text(let text): "'\(text.replacingOccurrences(of: "'", with: "''"))'"
case .blob(let data): "X'\(data.hex)'"
case .null: "NULL"
}
}
}
extension SQLiteValue: CustomStringConvertible {
/// A textual representation of the value, identical to `sqliteLiteral`.
public var description: String {
sqliteLiteral
}
}
private extension Data {
var hex: String {
map { String(format: "%02hhX", $0) }.joined()
}
}

View File

@@ -1,45 +1,41 @@
import Foundation
/// Represents different synchronous modes available for an SQLite database.
/// Represents the available synchronous modes for an SQLite database.
///
/// The synchronous mode determines how SQLite handles data synchronization with the database.
/// For more details, refer to [Synchronous Pragma](https://www.sqlite.org/pragma.html#pragma_synchronous).
public enum Synchronous: UInt8, SQLiteRawRepresentable {
/// Synchronous mode off. Disables synchronization for maximum performance.
/// The synchronous mode controls how thoroughly SQLite ensures that data is physically written to
/// disk. It defines the balance between durability, consistency, and performance during commits.
///
/// - SeeAlso: [PRAGMA synchronous](https://sqlite.org/pragma.html#pragma_synchronous)
public enum Synchronous: UInt8, SQLiteRepresentable {
/// Disables synchronization for maximum performance.
///
/// With synchronous OFF, SQLite continues without syncing as soon as it has handed data off
/// to the operating system. If the application running SQLite crashes, the data will be safe,
/// but the database might become corrupted if the operating system crashes or the computer loses
/// power before the data is written to the disk surface. On the other hand, commits can be orders
/// of magnitude faster with synchronous OFF.
/// With `synchronous=OFF`, SQLite does not wait for data to reach non-volatile storage before
/// continuing. The database may become inconsistent if the operating system crashes or power is
/// lost, although application-level crashes do not cause corruption.
/// Best suited for temporary databases or rebuildable data.
case off = 0
/// Normal synchronous mode.
/// Enables normal synchronization.
///
/// The SQLite database engine syncs at the most critical moments, but less frequently
/// than in FULL mode. While there is a very small chance of corruption in
/// `journal_mode=DELETE` on older filesystems during a power failure, WAL
/// mode is safe from corruption with synchronous=NORMAL. Modern filesystems
/// likely make DELETE mode safe too. However, WAL mode in synchronous=NORMAL
/// loses some durability, as a transaction committed in WAL mode might roll back
/// after a power loss or system crash. Transactions are still durable across application
/// crashes regardless of the synchronous setting or journal mode. This setting is a
/// good choice for most applications running in WAL mode.
/// SQLite performs syncs only at critical points. In WAL mode, this guarantees consistency but
/// not full durability: the most recent transactions might be lost after a power failure. In
/// rollback journal mode, there is a very small chance of corruption on older filesystems.
/// Recommended for most use cases where performance is preferred over strict durability.
case normal = 1
/// Full synchronous mode.
/// Enables full synchronization.
///
/// Uses the xSync method of the VFS to ensure that all content is safely written
/// to the disk surface prior to continuing. This ensures that an operating system
/// crash or power failure will not corrupt the database. FULL synchronous is very
/// safe but also slower. It is the most commonly used synchronous setting when
/// not in WAL mode.
/// SQLite calls the VFS `xSync` method to ensure that all data is written to disk before
/// continuing. Prevents corruption even after a system crash or power loss. Default mode for
/// rollback journals and fully ACID-compliant in WAL mode. Provides strong consistency and
/// isolation; durability may depend on filesystem behavior.
case full = 2
/// Extra synchronous mode.
/// Enables extra synchronization for maximum durability.
///
/// Similar to FULL mode, but ensures the directory containing the rollback journal
/// is synced after the journal is unlinked, providing additional durability in case of
/// power loss shortly after a commit.
/// Extends `FULL` by also syncing the directory that contained the rollback journal after it
/// is removed, ensuring durability even if power is lost immediately after a commit. Guarantees
/// full ACID compliance in both rollback and WAL modes. Recommended for systems where
/// durability is more important than performance.
case extra = 3
}

View File

@@ -1,39 +1,35 @@
import Foundation
/// An enumeration representing different types of SQLite transactions.
/// Represents the transaction modes supported by SQLite.
///
/// SQLite transactions determine how the database engine handles concurrency and locking
/// during a transaction. The default transaction behavior is DEFERRED. For more detailed information
/// about SQLite transactions, refer to the [SQLite documentation](https://www.sqlite.org/lang_transaction.html).
/// A transaction defines how the database manages concurrency and locking. The transaction type
/// determines when a write lock is acquired and how other connections can access the database
/// during the transaction.
///
/// - SeeAlso: [Transaction](https://sqlite.org/lang_transaction.html)
public enum TransactionType: String, CustomStringConvertible {
/// A deferred transaction.
/// Defers the start of the transaction until the first database access.
///
/// A deferred transaction does not start until the database is first accessed. Internally,
/// the `BEGIN DEFERRED` statement merely sets a flag on the database connection to prevent
/// the automatic commit that normally occurs when the last statement finishes. If the first
/// statement after `BEGIN DEFERRED` is a `SELECT`, a read transaction begins. If it is a write
/// statement, a write transaction starts. Subsequent write operations may upgrade the transaction
/// to a write transaction if possible, or return `SQLITE_BUSY`. The transaction persists until
/// an explicit `COMMIT` or `ROLLBACK` or until a rollback is provoked by an error or an `ON CONFLICT ROLLBACK` clause.
/// With `BEGIN DEFERRED`, no locks are acquired immediately. If the first statement is a read
/// (`SELECT`), a read transaction begins. If it is a write statement, a write transaction
/// begins instead. Deferred transactions allow greater concurrency and are the default mode.
case deferred = "DEFERRED"
/// An immediate transaction.
/// Starts a write transaction immediately.
///
/// An immediate transaction starts a new write immediately, without waiting for the first
/// write statement. The `BEGIN IMMEDIATE` statement may fail with `SQLITE_BUSY` if another
/// write transaction is active on a different database connection.
/// With `BEGIN IMMEDIATE`, a reserved lock is acquired right away to ensure that no other
/// connection can start a conflicting write. The statement may fail with `SQLITE_BUSY` if
/// another write transaction is already active.
case immediate = "IMMEDIATE"
/// An exclusive transaction.
/// Starts an exclusive write transaction.
///
/// Similar to `IMMEDIATE`, an exclusive transaction starts a write immediately. However,
/// in non-WAL modes, `EXCLUSIVE` prevents other database connections from reading the database
/// while the transaction is in progress. In WAL mode, `EXCLUSIVE` behaves the same as `IMMEDIATE`.
/// With `BEGIN EXCLUSIVE`, a write lock is acquired immediately. In rollback journal mode, it
/// also prevents other connections from reading the database while the transaction is active.
/// In WAL mode, it behaves the same as `.immediate`.
case exclusive = "EXCLUSIVE"
/// A textual representation of the transaction type.
///
/// Returns the raw value of the transaction type (e.g., "DEFERRED", "IMMEDIATE", "EXCLUSIVE").
public var description: String {
rawValue
}