Merge branch 'develop'
This commit is contained in:
@@ -41,7 +41,7 @@ import PackageDescription
|
||||
let package = Package(
|
||||
name: "YourProject",
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/angd-dev/data-lite-core.git", from: "1.0.0")
|
||||
.package(url: "https://github.com/angd-dev/data-lite-core.git", from: "1.1.0")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
@@ -56,7 +56,7 @@ let package = Package(
|
||||
|
||||
## Additional Resources
|
||||
|
||||
For more information and usage examples, see the [documentation](https://docs.angd.dev/?package=data-lite-core&version=1.0.0).
|
||||
For more information and usage examples, see the [documentation](https://docs.angd.dev/?package=data-lite-core&version=1.1.0).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ extension Connection {
|
||||
/// Two formats are supported:
|
||||
/// - a passphrase, which undergoes key derivation;
|
||||
/// - a raw 256-bit key (32 bytes) passed without transformation.
|
||||
public enum Key {
|
||||
public enum Key: Sendable {
|
||||
/// A human-readable passphrase used for key derivation.
|
||||
///
|
||||
/// The passphrase is supplied as-is and processed by the underlying key derivation
|
||||
|
||||
@@ -131,6 +131,14 @@ extension Connection: ConnectionProtocol {
|
||||
sqlite3_db_readonly(connection, "main") == 1
|
||||
}
|
||||
|
||||
public var changes: Int64 {
|
||||
sqlite3_changes64(connection)
|
||||
}
|
||||
|
||||
public var totalChanges: Int64 {
|
||||
sqlite3_total_changes64(connection)
|
||||
}
|
||||
|
||||
public static func initialize() throws(SQLiteError) {
|
||||
let status = sqlite3_initialize()
|
||||
guard status == SQLITE_OK else {
|
||||
|
||||
@@ -6,7 +6,7 @@ import Foundation
|
||||
/// journal for rollback and recovery.
|
||||
///
|
||||
/// - SeeAlso: [journal_mode](https://sqlite.org/pragma.html#pragma_journal_mode)
|
||||
public enum JournalMode: String, SQLiteRepresentable {
|
||||
public enum JournalMode: String, SQLiteRepresentable, Sendable {
|
||||
/// DELETE journal mode.
|
||||
///
|
||||
/// This is the default behavior. The rollback journal is deleted at the conclusion of each
|
||||
|
||||
@@ -7,7 +7,7 @@ import Foundation
|
||||
/// as the database name, table, and affected row ID.
|
||||
///
|
||||
/// - SeeAlso: [Data Change Notification Callbacks](https://sqlite.org/c3ref/update_hook.html)
|
||||
public enum SQLiteAction {
|
||||
public enum SQLiteAction: Hashable, Sendable {
|
||||
/// A new row was inserted into a table.
|
||||
///
|
||||
/// - Parameters:
|
||||
|
||||
@@ -6,7 +6,7 @@ import Foundation
|
||||
/// 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 {
|
||||
public enum Synchronous: UInt8, SQLiteRepresentable, Sendable {
|
||||
/// Disables synchronization for maximum performance.
|
||||
///
|
||||
/// With `synchronous=OFF`, SQLite does not wait for data to reach non-volatile storage before
|
||||
|
||||
@@ -7,7 +7,7 @@ import Foundation
|
||||
/// during the transaction.
|
||||
///
|
||||
/// - SeeAlso: [Transaction](https://sqlite.org/lang_transaction.html)
|
||||
public enum TransactionType: String, CustomStringConvertible {
|
||||
public enum TransactionType: String, CustomStringConvertible, Sendable {
|
||||
/// Defers the start of the transaction until the first database access.
|
||||
///
|
||||
/// With `BEGIN DEFERRED`, no locks are acquired immediately. If the first statement is a read
|
||||
|
||||
@@ -12,6 +12,8 @@ import Foundation
|
||||
///
|
||||
/// - ``isAutocommit``
|
||||
/// - ``isReadonly``
|
||||
/// - ``changes``
|
||||
/// - ``totalChanges``
|
||||
///
|
||||
/// ### Accessing PRAGMA Values
|
||||
///
|
||||
@@ -84,6 +86,14 @@ public protocol ConnectionProtocol: AnyObject {
|
||||
/// - SeeAlso: [Determine if a database is read-only](https://sqlite.org/c3ref/db_readonly.html)
|
||||
var isReadonly: Bool { get }
|
||||
|
||||
/// The number of rows modified by the most recent write operation.
|
||||
/// - SeeAlso: [Count The Number Of Rows Modified](https://sqlite.org/c3ref/changes.html)
|
||||
var changes: Int64 { get }
|
||||
|
||||
/// The total number of rows modified since this connection was opened.
|
||||
/// - SeeAlso: [Total Number Of Rows Modified](https://sqlite.org/c3ref/total_changes.html)
|
||||
var totalChanges: Int64 { get }
|
||||
|
||||
// MARK: - PRAGMA Accessors
|
||||
|
||||
/// The busy timeout of the connection, in milliseconds.
|
||||
|
||||
@@ -63,6 +63,63 @@ struct ConnectionTests {
|
||||
#expect(connection.isReadonly == expected)
|
||||
}
|
||||
|
||||
@Test func changes() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory, options: [.create, .readwrite]
|
||||
)
|
||||
|
||||
try connection.execute(sql: "CREATE TABLE t (id INT PRIMARY KEY)")
|
||||
#expect(connection.changes == 0)
|
||||
|
||||
try connection.execute(sql: "INSERT INTO t (id) VALUES (1),(2)")
|
||||
#expect(connection.changes == 2)
|
||||
|
||||
try connection.execute(sql: "UPDATE t SET id = 3 WHERE id = 1")
|
||||
#expect(connection.changes == 1)
|
||||
|
||||
try connection.execute(sql: "DELETE FROM t WHERE id = 2")
|
||||
#expect(connection.changes == 1)
|
||||
|
||||
try connection.execute(sql: "UPDATE t SET id = 3 WHERE id = -1")
|
||||
#expect(connection.changes == 0)
|
||||
|
||||
try connection.execute(sql: "INSERT INTO t (id) VALUES (4),(5)")
|
||||
try connection.execute(sql: "SELECT * FROM t")
|
||||
#expect(connection.changes == 2)
|
||||
}
|
||||
|
||||
@Test func totalChanges() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory, options: [.create, .readwrite]
|
||||
)
|
||||
|
||||
try connection.execute(sql: "CREATE TABLE t (id INT PRIMARY KEY)")
|
||||
#expect(connection.totalChanges == 0)
|
||||
|
||||
try connection.execute(sql: "INSERT INTO t (id) VALUES (1),(2)")
|
||||
#expect(connection.totalChanges == 2)
|
||||
|
||||
try connection.execute(sql: "UPDATE t SET id = 3 WHERE id = 1")
|
||||
#expect(connection.totalChanges == 3)
|
||||
|
||||
try connection.execute(sql: "DELETE FROM t WHERE id = 2")
|
||||
#expect(connection.totalChanges == 4)
|
||||
|
||||
// No-op update — does not increase totalChanges
|
||||
try connection.execute(sql: "UPDATE t SET id = 3 WHERE id = -1")
|
||||
#expect(connection.totalChanges == 4)
|
||||
|
||||
// Read-only statements do not affect totals
|
||||
try connection.execute(sql: "SELECT * FROM t")
|
||||
#expect(connection.totalChanges == 4)
|
||||
|
||||
try connection.execute(sql: "INSERT INTO t (id) VALUES (4),(5)")
|
||||
#expect(connection.totalChanges == 6)
|
||||
|
||||
try connection.execute(sql: "DELETE FROM t")
|
||||
#expect(connection.totalChanges == 9)
|
||||
}
|
||||
|
||||
@Test func testBusyTimeout() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory, options: [.create, .readwrite]
|
||||
|
||||
Reference in New Issue
Block a user