Skip to content

Commit db695cf

Browse files
committed
Merge branch 'development'
2 parents c5d02ea + 76a7be8 commit db695cf

File tree

9 files changed

+101
-16
lines changed

9 files changed

+101
-16
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one exception:
77

88
#### 7.x Releases
99

10-
- `7.7.x` Releases - [7.7.0](#770)
10+
- `7.7.x` Releases - [7.7.0](#770) - [7.7.1](#771)
1111
- `7.6.x` Releases - [7.6.0](#760) - [7.6.1](#761)
1212
- `7.5.x` Releases - [7.5.0](#750)
1313
- `7.4.x` Releases - [7.4.0](#740) - [7.4.1](#741)
@@ -139,6 +139,12 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one exception:
139139

140140
---
141141

142+
## 7.7.1
143+
144+
Released September 29, 2025
145+
146+
- **Fixed**: Fix the save() method for record types with attached triggers by [@groue](https://github.com/groue) in [#1822](https://github.com/groue/GRDB.swift/pull/1822)
147+
142148
## 7.7.0
143149

144150
Released September 23, 2025

GRDB.swift.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'GRDB.swift'
3-
s.version = '7.7.0'
3+
s.version = '7.7.1'
44

55
s.license = { :type => 'MIT', :file => 'LICENSE' }
66
s.summary = 'A toolkit for SQLite databases, with a focus on application development.'

GRDB/Core/Database.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,6 +2018,34 @@ extension Database {
20182018
}
20192019
#endif
20202020

2021+
extension Database {
2022+
/// Returns the count of changes executed by one statement execution.
2023+
func countChanges<T>(_ count: inout Int, forTable tableName: String, updates: () throws -> T) throws -> T {
2024+
// Database.changesCount calls sqlite3_changes(), whose documentation says:
2025+
//
2026+
// > https://sqlite.org/c3ref/changes.html
2027+
// > Changes to a view that are intercepted by INSTEAD OF triggers are not counted.
2028+
//
2029+
// We want to support INSTEAD OF triggers, so we prefer to use
2030+
// sqlite3_total_changes() for views.
2031+
//
2032+
// At the same time, FTS5 has sqlite3_total_changes() report changes
2033+
// even when database is not changed (https://github.com/groue/GRDB.swift/issues/1820)
2034+
//
2035+
// Well, let's do our best:
2036+
if try viewExists(tableName) {
2037+
let prevCount = totalChangesCount
2038+
let result = try updates()
2039+
count = totalChangesCount - prevCount
2040+
return result
2041+
} else {
2042+
let result = try updates()
2043+
count = changesCount
2044+
return result
2045+
}
2046+
}
2047+
}
2048+
20212049
extension Database {
20222050

20232051
// MARK: - Database-Related Types

GRDB/QueryInterface/Request/QueryInterfaceRequest.swift

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -635,9 +635,11 @@ extension QueryInterfaceRequest {
635635
@discardableResult
636636
public func deleteAll(_ db: Database) throws -> Int {
637637
let statement = try SQLQueryGenerator(relation: relation).makeDeleteStatement(db)
638-
let prevCount = db.totalChangesCount
639-
try statement.execute()
640-
return db.totalChangesCount - prevCount
638+
var changesCount = 0
639+
try db.countChanges(&changesCount, forTable: relation.source.tableName) {
640+
try statement.execute()
641+
}
642+
return changesCount
641643
}
642644
}
643645

@@ -1136,9 +1138,11 @@ extension QueryInterfaceRequest {
11361138
// database not hit
11371139
return 0
11381140
}
1139-
let prevCount = db.totalChangesCount
1140-
try updateStatement.execute()
1141-
return db.totalChangesCount - prevCount
1141+
var changesCount = 0
1142+
try db.countChanges(&changesCount, forTable: relation.source.tableName) {
1143+
try updateStatement.execute()
1144+
}
1145+
return changesCount
11421146
}
11431147

11441148
/// Updates matching rows, and returns the number of updated rows.

GRDB/Record/MutablePersistableRecord+Delete.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@ extension MutablePersistableRecord {
5353
// Nil primary key
5454
return false
5555
}
56-
let prevCount = db.totalChangesCount
57-
try statement.execute()
58-
return (db.totalChangesCount - prevCount) > 0
56+
var changesCount = 0
57+
try db.countChanges(&changesCount, forTable: type(of: self).databaseTableName) {
58+
try statement.execute()
59+
}
60+
return changesCount > 0
5961
}
6062
}

GRDB/Record/MutablePersistableRecord+Update.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -956,9 +956,10 @@ extension MutablePersistableRecord {
956956
// Nil primary key
957957
try dao.recordNotFound()
958958
}
959-
let prevCount = db.totalChangesCount
960-
let returned = try fetch(statement)
961-
let changesCount = db.totalChangesCount - prevCount
959+
var changesCount = 0
960+
let returned = try db.countChanges(&changesCount, forTable: type(of: self).databaseTableName) {
961+
try fetch(statement)
962+
}
962963
if changesCount == 0 {
963964
// No row was updated
964965
try dao.recordNotFound()

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
---
2727

28-
**Latest release**: September 23, 2025 • [version 7.7.0](https://github.com/groue/GRDB.swift/tree/v7.7.0) • [CHANGELOG](CHANGELOG.md) • [Migrating From GRDB 6 to GRDB 7](Documentation/GRDB7MigrationGuide.md)
28+
**Latest release**: September 29, 2025 • [version 7.7.1](https://github.com/groue/GRDB.swift/tree/v7.7.0) • [CHANGELOG](CHANGELOG.md) • [Migrating From GRDB 6 to GRDB 7](Documentation/GRDB7MigrationGuide.md)
2929

3030
**Requirements**: iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 7.0+ &bull; SQLite 3.20.0+ &bull; Swift 6+ / Xcode 16+
3131

Support/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>FMWK</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>7.7.0</string>
18+
<string>7.7.1</string>
1919
<key>CFBundleSignature</key>
2020
<string>????</string>
2121
<key>CFBundleVersion</key>

Tests/GRDBTests/MutablePersistableRecordTests.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2796,3 +2796,47 @@ extension MutablePersistableRecordTests {
27962796
} catch DatabaseError.SQLITE_MISUSE { }
27972797
}
27982798
}
2799+
2800+
#if SQLITE_ENABLE_FTS5
2801+
class Issue1820Tests: GRDBTestCase {
2802+
// Regression test for https://github.com/groue/GRDB.swift/issues/1820
2803+
func testIssue1820() throws {
2804+
struct Serving: Codable, FetchableRecord, PersistableRecord {
2805+
let id: UUID
2806+
var description: String
2807+
var foodId: String
2808+
2809+
static let author = hasOne(Food.self)
2810+
}
2811+
2812+
struct Food: Codable, FetchableRecord, PersistableRecord {
2813+
let id: UUID
2814+
var name: String
2815+
var foodId: String
2816+
}
2817+
2818+
let dbQueue = try makeDatabaseQueue()
2819+
try dbQueue.write { db in
2820+
try db.create(table: "food") { t in
2821+
t.column("id", .blob).primaryKey()
2822+
t.column("name", .text)
2823+
t.column("foodId", .text).unique()
2824+
}
2825+
2826+
try db.create(table: "serving") { t in
2827+
t.column("id", .blob).primaryKey()
2828+
t.column("description", .text)
2829+
t.column("foodId", .text).references("food", column: "foodId")
2830+
}
2831+
2832+
try db.create(virtualTable: "food_fts", using: FTS5()) { t in
2833+
t.synchronize(withTable: "food")
2834+
t.column("name")
2835+
}
2836+
2837+
try Food(id: UUID(), name: "Apple", foodId: "apple").save(db)
2838+
try Serving(id: UUID(), description: "Apple", foodId: "apple").save(db)
2839+
}
2840+
}
2841+
}
2842+
#endif

0 commit comments

Comments
 (0)