Skip to content

Commit e82a036

Browse files
committed
Merge branch 'development'
2 parents d70032c + 51c9071 commit e82a036

24 files changed

+742
-220
lines changed

CHANGELOG.md

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

9898
---
9999

100+
## 6.0.0-beta.3
101+
102+
Released August 25, 2022 • [diff](https://github.com/groue/GRDB.swift/compare/v6.0.0-beta...v6.0.0-beta.2)
103+
104+
- **Fix**: [#1268](https://github.com/groue/GRDB.swift/pull/1268) by [@groue](https://github.com/groue): Fix SQL generation of CHECK constraints
105+
- **Breaking**: The `Column` type is no longer `Equatable`
106+
- **Documentation Update**: [Migrating From GRDB 5 to GRDB 6](Documentation/GRDB6MigrationGuide.md) describes in detail how to update records that customize their persistence methods.
107+
- **Documentation Update**: The [Single-Row Tables](Documentation/SingleRowTables.md) guide was updated for the new persistence callbacks.
108+
100109
## 6.0.0-beta.2
101110

102111
Released August 23, 2022 • [diff](https://github.com/groue/GRDB.swift/compare/v6.0.0-beta...v6.0.0-beta.2)
103112

104113
- **New**: Extended UPSERT apis with the ability to define the conflict target, and the assignments performed in case of conflicts.
105-
- **Documentation**: A new [Upsert](README.md#upsert) chapter describes upserts in detail.
114+
- **Documentation Update**: A new [Upsert](README.md#upsert) chapter describes upserts in detail.
106115

107116
## 6.0.0-beta
108117

Documentation/FullTextSearch.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ let pattern = FTS3Pattern(matchingAnyTokenIn: "") // nil
304304
let pattern = FTS3Pattern(matchingAnyTokenIn: "*") // nil
305305
```
306306

307-
FTS3Pattern are regular [values](../README.md#values). You can use them as query [arguments](http://groue.github.io/GRDB.swift/docs/6.0.0-beta.2/Structs/StatementArguments.html):
307+
FTS3Pattern are regular [values](../README.md#values). You can use them as query [arguments](http://groue.github.io/GRDB.swift/docs/6.0.0-beta.3/Structs/StatementArguments.html):
308308

309309
```swift
310310
let documents = try Document.fetchAll(db,
@@ -587,7 +587,7 @@ let pattern = FTS5Pattern(matchingAnyTokenIn: "") // nil
587587
let pattern = FTS5Pattern(matchingAnyTokenIn: "*") // nil
588588
```
589589

590-
FTS5Pattern are regular [values](../README.md#values). You can use them as query [arguments](http://groue.github.io/GRDB.swift/docs/6.0.0-beta.2/Structs/StatementArguments.html):
590+
FTS5Pattern are regular [values](../README.md#values). You can use them as query [arguments](http://groue.github.io/GRDB.swift/docs/6.0.0-beta.3/Structs/StatementArguments.html):
591591

592592
```swift
593593
let documents = try Document.fetchAll(db,

Documentation/GRDB6MigrationGuide.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,32 @@ The record protocols have been refactored. We tried to keep the amount of modifi
172172

173173
- **PersistableRecord types now customize persistence methods with "persistence callbacks"**.
174174

175-
It is no longer possible to override persistence methods such as `insert` or `update`. Customizing the persistence methods is now possible with callbacks such as `willSave`, `willInsert`, or `didDelete` (see [Persistence Callbacks](../README.md#persistence-callbacks) for the full list of callbacks).
175+
It is no longer possible to override persistence methods such as `insert` or `update`. Customizing the persistence methods is now possible with callbacks such as `willSave`, `willInsert`, or `didDelete` (see [persistence callbacks] for the full list of callbacks).
176176

177-
For example, let's consider a record that performs some validation before insertion and updates. In GRDB 5, this would look like:
177+
**You have to remove the methods below from your own code base**:
178+
179+
```swift
180+
// GRDB 6: remove those methods from your code
181+
func insert(_ db: Database) throws
182+
func didInsert(with rowID: Int64, for column: String?)
183+
func update(_ db: Database, columns: Set<String>) throws
184+
func save(_ db: Database) throws
185+
func delete(_ db: Database) throws -> Bool
186+
func exists(_ db: Database) throws -> Bool
187+
```
188+
189+
- `insert(_:)`: customization is now made with [persistence callbacks].
190+
- `didInsert(with:for:)`: this method was renamed `didInsert(_:)` (see previous bullet point).
191+
- `update(_:columns:)`: customization is now made with [persistence callbacks].
192+
- `save(_:)`: customization is now made with [persistence callbacks].
193+
- `delete(_:)`: customization is now made with [persistence callbacks].
194+
- `exists(_:)`: this method is no longer customizable.
195+
196+
To help you update your applications with persistence callbacks, let's look at two examples.
197+
198+
First, check the updated [Single-Row Tables](SingleRowTables.md) guide, if your application defines a "singleton record".
199+
200+
Next, let's consider a record that performs some validation before insertion and updates. In GRDB 5, this would look like:
178201

179202
```swift
180203
// GRDB 5
@@ -351,3 +374,5 @@ The record protocols have been refactored. We tried to keep the amount of modifi
351374
print("Succesful commit")
352375
}
353376
```
377+
378+
[persistence callbacks]: ../README.md#persistence-callbacks

Documentation/Migrations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ try dbQueue.read { db in
7777
}
7878
```
7979

80-
See the [DatabaseMigrator reference](http://groue.github.io/GRDB.swift/docs/6.0.0-beta.2/Structs/DatabaseMigrator.html) for more migrator methods.
80+
See the [DatabaseMigrator reference](http://groue.github.io/GRDB.swift/docs/6.0.0-beta.3/Structs/DatabaseMigrator.html) for more migrator methods.
8181

8282

8383
## The `eraseDatabaseOnSchemaChange` Option

Documentation/SingleRowTables.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,14 @@ We make our record able to access the database:
116116
extension AppConfiguration: FetchableRecord, PersistableRecord {
117117
```
118118

119-
We have seen in the [The Single-Row Table] chapter that by default, updates throw an error if the database table is empty. To avoid this error, we instruct GRDB to perform an insert in case of a failed update (see [Persistence Methods] for more information):
119+
We have seen in the [The Single-Row Table] chapter that by default, updates throw an error if the database table is empty. To avoid this error, we instruct GRDB to insert the missing default configuration before attempting to update (see [Persistence Callbacks] for more information about the `willSave` method):
120120

121121
```swift
122122
// Customize the default PersistableRecord behavior
123-
func update(_ db: Database, columns: Set<String>) throws {
124-
do {
125-
try performUpdate(db, columns: columns)
126-
} catch PersistenceError.recordNotFound {
127-
// No row was updated: perform an insert
128-
try performInsert(db)
123+
func willUpdate(_ db: Database, columns: Set<String>) throws {
124+
// Insert the default configuration if it does not exist yet.
125+
if try !exists(db) {
126+
try AppConfiguration.default.insert(db)
129127
}
130128
}
131129
```
@@ -165,12 +163,13 @@ try dbQueue.write { db in
165163
try config.update(db)
166164
try config.save(db)
167165
try config.insert(db)
166+
try config.upsert(db)
168167
}
169168
```
170169

171-
The three `update`, `save` and `insert` methods can be used interchangeably: all three make sure the configuration is stored in the database.
170+
The four `update`, `save`, `insert` and `upsert` methods can be used interchangeably. They all make sure the configuration is stored in the database.
172171

173-
The `updateChanges` method only updates the values changed by its closure argument (and performs an insert if the database table is empty).
172+
The `updateChanges` method only updates the values changed by its closure argument (and performs an initial insert of default configuration if the database table is empty).
174173

175174
See [Persistence Methods] for more information.
176175

@@ -215,12 +214,10 @@ extension AppConfiguration {
215214
// Database Access
216215
extension AppConfiguration: FetchableRecord, PersistableRecord {
217216
// Customize the default PersistableRecord behavior
218-
func update(_ db: Database, columns: Set<String>) throws {
219-
do {
220-
try performUpdate(db, columns: columns)
221-
} catch PersistenceError.recordNotFound {
222-
// No row was updated: perform an insert
223-
try performInsert(db)
217+
func willUpdate(_ db: Database, columns: Set<String>) throws {
218+
// Insert the default configuration if it does not exist yet.
219+
if try !exists(db) {
220+
try AppConfiguration.default.insert(db)
224221
}
225222
}
226223

@@ -239,4 +236,5 @@ extension AppConfiguration: FetchableRecord, PersistableRecord {
239236
[The Single-Row Record]: #the-single-row-record
240237
[Wrap-Up]: #wrap-up
241238
[DRY]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
239+
[Persistence Callbacks]: ../README.md#persistence-callbacks
242240
[Persistence Methods]: ../README.md#persistence-methods

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 = '6.0.0-beta.2'
3+
s.version = '6.0.0-beta.3'
44

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

GRDB.xcodeproj/project.pbxproj

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@
100100
5616AAF1207CD45E00AC3664 /* RequestProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5616AAF0207CD45E00AC3664 /* RequestProtocols.swift */; };
101101
5616AAF2207CD45E00AC3664 /* RequestProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5616AAF0207CD45E00AC3664 /* RequestProtocols.swift */; };
102102
5616AAF3207CD45E00AC3664 /* RequestProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5616AAF0207CD45E00AC3664 /* RequestProtocols.swift */; };
103+
5616B4FB28B5F5220052017E /* SingletonRecordTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5616B4FA28B5F5220052017E /* SingletonRecordTest.swift */; };
104+
5616B4FC28B5F5220052017E /* SingletonRecordTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5616B4FA28B5F5220052017E /* SingletonRecordTest.swift */; };
105+
5616B4FD28B5F5220052017E /* SingletonRecordTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5616B4FA28B5F5220052017E /* SingletonRecordTest.swift */; };
103106
5617294E223533F40006E219 /* EncodableRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56172947223533F40006E219 /* EncodableRecord.swift */; };
104107
5617294F223533F40006E219 /* EncodableRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56172947223533F40006E219 /* EncodableRecord.swift */; };
105108
56172950223533F40006E219 /* EncodableRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56172947223533F40006E219 /* EncodableRecord.swift */; };
@@ -1366,6 +1369,7 @@
13661369
5615B287222B17BF00061C1C /* AssociationHasOneThroughDecodableRecordTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssociationHasOneThroughDecodableRecordTests.swift; sourceTree = "<group>"; };
13671370
561667001D08A49900ADD404 /* FoundationNSDecimalNumberTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoundationNSDecimalNumberTests.swift; sourceTree = "<group>"; };
13681371
5616AAF0207CD45E00AC3664 /* RequestProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestProtocols.swift; sourceTree = "<group>"; };
1372+
5616B4FA28B5F5220052017E /* SingletonRecordTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingletonRecordTest.swift; sourceTree = "<group>"; };
13691373
56172947223533F40006E219 /* EncodableRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EncodableRecord.swift; sourceTree = "<group>"; };
13701374
561CFA7123735015000C8BAA /* TableRecordUpdateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRecordUpdateTests.swift; sourceTree = "<group>"; };
13711375
561CFA912376E546000C8BAA /* AssociationHasManyThroughOrderingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssociationHasManyThroughOrderingTests.swift; sourceTree = "<group>"; };
@@ -2387,8 +2391,9 @@
23872391
56A238251B9C74A90082EB20 /* Record */ = {
23882392
isa = PBXGroup;
23892393
children = (
2390-
5674A7251F30A8EF0095F066 /* FetchableRecord */,
23912394
564E73DE203D50B9000C443C /* JoinSupportTests.swift */,
2395+
5616B4FA28B5F5220052017E /* SingletonRecordTest.swift */,
2396+
5674A7251F30A8EF0095F066 /* FetchableRecord */,
23922397
560B3FA41C19DFF800C58EC7 /* PersistableRecord */,
23932398
56176C9E1EACEDF9000F3F2B /* Record */,
23942399
56176C9C1EACEA8C000F3F2B /* TableRecord */,
@@ -3434,6 +3439,7 @@
34343439
5674A72D1F30A9090095F066 /* FetchableRecordDecodableTests.swift in Sources */,
34353440
56419C5F24A51999004967E1 /* Inverted.swift in Sources */,
34363441
560432A4228F1668009D3FE2 /* AssociationPrefetchingObservationTests.swift in Sources */,
3442+
5616B4FC28B5F5220052017E /* SingletonRecordTest.swift in Sources */,
34373443
566A84412041914000E50BFD /* MutablePersistableRecordChangesTests.swift in Sources */,
34383444
56176C701EACCCC9000F3F2B /* FTS5WrapperTokenizerTests.swift in Sources */,
34393445
56FEE7FF1F47253700D930EA /* TableRecordTests.swift in Sources */,
@@ -3669,6 +3675,7 @@
36693675
563B06CA2185D2E500B38F35 /* ValueObservationFetchTests.swift in Sources */,
36703676
56D496541D812F5B008276D7 /* SQLExpressionLiteralTests.swift in Sources */,
36713677
56D496961D81317B008276D7 /* PersistableRecordTests.swift in Sources */,
3678+
5616B4FB28B5F5220052017E /* SingletonRecordTest.swift in Sources */,
36723679
56419C5724A51998004967E1 /* Inverted.swift in Sources */,
36733680
560432A3228F1668009D3FE2 /* AssociationPrefetchingObservationTests.swift in Sources */,
36743681
5698AC9E1DA4B0430056AF8C /* FTS4TableBuilderTests.swift in Sources */,
@@ -4052,6 +4059,7 @@
40524059
AAA4DD73230F262000C74B15 /* FetchableRecordDecodableTests.swift in Sources */,
40534060
56419C6724A5199B004967E1 /* Inverted.swift in Sources */,
40544061
AAA4DD74230F262000C74B15 /* AssociationPrefetchingObservationTests.swift in Sources */,
4062+
5616B4FD28B5F5220052017E /* SingletonRecordTest.swift in Sources */,
40554063
AAA4DD75230F262000C74B15 /* MutablePersistableRecordChangesTests.swift in Sources */,
40564064
AAA4DD76230F262000C74B15 /* FTS5WrapperTokenizerTests.swift in Sources */,
40574065
AAA4DD77230F262000C74B15 /* TableRecordTests.swift in Sources */,

GRDB/QueryInterface/SQL/Column.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ extension ColumnExpression where Self == Column {
6363
/// Instead, adopt the ColumnExpression protocol.
6464
///
6565
/// See <https://github.com/groue/GRDB.swift#the-query-interface>
66-
public struct Column: ColumnExpression, Equatable {
66+
public struct Column: ColumnExpression {
6767
/// The hidden rowID column
6868
public static let rowID = Column("rowid")
6969

@@ -79,12 +79,6 @@ public struct Column: ColumnExpression, Equatable {
7979
public init(_ codingKey: some CodingKey) {
8080
self.name = codingKey.stringValue
8181
}
82-
83-
// Avoid a wrong resolution when BUILD_LIBRARY_FOR_DISTRIBUTION is set
84-
@_disfavoredOverload
85-
public static func == (lhs: Column, rhs: Column) -> Bool {
86-
lhs.name == rhs.name
87-
}
8882
}
8983

9084
/// Support for column enums:

GRDB/Record/MutablePersistableRecord+Delete.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@ extension MutablePersistableRecord {
2929
public func delete(_ db: Database) throws -> Bool {
3030
try willDelete(db)
3131

32-
var deleted = false
32+
var deleted: Bool?
3333
try aroundDelete(db) {
3434
deleted = try deleteWithoutCallbacks(db)
35-
return deleted
35+
return deleted!
3636
}
3737

38+
guard let deleted else {
39+
try persistenceCallbackMisuse("aroundDelete")
40+
}
3841
didDelete(deleted: deleted)
3942
return deleted
4043
}

GRDB/Record/MutablePersistableRecord+Insert.swift

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ extension MutablePersistableRecord {
3232
{
3333
try willSave(db)
3434

35-
var saved: PersistenceSuccess!
35+
var saved: PersistenceSuccess?
3636
try aroundSave(db) {
3737
let inserted = try insertWithCallbacks(db, onConflict: conflictResolution)
3838
saved = PersistenceSuccess(inserted)
39-
return saved
39+
return saved!
4040
}
4141

42+
guard let saved else {
43+
try persistenceCallbackMisuse("aroundSave")
44+
}
4245
didSave(saved)
4346
}
4447

@@ -215,18 +218,20 @@ extension MutablePersistableRecord {
215218

216219
try willSave(db)
217220

218-
var inserted: InsertionSuccess!
219-
var returned: T!
221+
var success: (inserted: InsertionSuccess, returned: T)?
220222
try aroundSave(db) {
221-
(inserted, returned) = try insertAndFetchWithCallbacks(
223+
success = try insertAndFetchWithCallbacks(
222224
db, onConflict: conflictResolution,
223225
selection: selection,
224226
fetch: fetch)
225-
return PersistenceSuccess(inserted)
227+
return PersistenceSuccess(success!.inserted)
226228
}
227229

228-
didSave(PersistenceSuccess(inserted))
229-
return returned
230+
guard let success else {
231+
try persistenceCallbackMisuse("aroundSave")
232+
}
233+
didSave(PersistenceSuccess(success.inserted))
234+
return success.returned
230235
}
231236
#else
232237
/// Executes an `INSERT ... RETURNING ...` statement, and returns the
@@ -374,18 +379,20 @@ extension MutablePersistableRecord {
374379

375380
try willSave(db)
376381

377-
var inserted: InsertionSuccess!
378-
var returned: T!
382+
var success: (inserted: InsertionSuccess, returned: T)?
379383
try aroundSave(db) {
380-
(inserted, returned) = try insertAndFetchWithCallbacks(
384+
success = try insertAndFetchWithCallbacks(
381385
db, onConflict: conflictResolution,
382386
selection: selection,
383387
fetch: fetch)
384-
return PersistenceSuccess(inserted)
388+
return PersistenceSuccess(success!.inserted)
385389
}
386390

387-
didSave(PersistenceSuccess(inserted))
388-
return returned
391+
guard let success else {
392+
try persistenceCallbackMisuse("aroundSave")
393+
}
394+
didSave(PersistenceSuccess(success.inserted))
395+
return success.returned
389396
}
390397
#endif
391398
}
@@ -419,18 +426,20 @@ extension MutablePersistableRecord {
419426
{
420427
try willInsert(db)
421428

422-
var inserted: InsertionSuccess!
423-
var returned: T!
429+
var success: (inserted: InsertionSuccess, returned: T)?
424430
try aroundInsert(db) {
425-
(inserted, returned) = try insertAndFetchWithoutCallbacks(
431+
success = try insertAndFetchWithoutCallbacks(
426432
db, onConflict: conflictResolution,
427433
selection: selection,
428434
fetch: fetch)
429-
return inserted
435+
return success!.inserted
430436
}
431437

432-
didInsert(inserted)
433-
return (inserted, returned)
438+
guard let success else {
439+
try persistenceCallbackMisuse("aroundInsert")
440+
}
441+
didInsert(success.inserted)
442+
return success
434443
}
435444

436445
/// Executes an `INSERT` statement, with `RETURNING` clause if `selection`

0 commit comments

Comments
 (0)