Skip to content

Commit 78448cf

Browse files
committed
Merge branch 'development'
2 parents 4b934fd + 30de985 commit 78448cf

24 files changed

+510
-51
lines changed

CHANGELOG.md

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

88
#### 6.x Releases
99

10+
- `6.28.x` Releases - [6.28.0](#6280)
1011
- `6.27.x` Releases - [6.27.0](#6270)
1112
- `6.26.x` Releases - [6.26.0](#6260)
1213
- `6.25.x` Releases - [6.25.0](#6250)
@@ -125,6 +126,15 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one exception:
125126

126127
---
127128

129+
## 6.28.0
130+
131+
Released July 11, 2024
132+
133+
- **New**: [#1570](https://github.com/groue/GRDB.swift/pull/1570) by [@groue](https://github.com/groue): Support single-value encoding
134+
- **New**: Added `QueryInterfaceRequest.deleteAndFetchIds(_:)` which returns the set of deleted ids.
135+
- **New**: Added `Set` methods `union`, `formUnion`, `intersection` and `formIntersection` that accept a cursor.
136+
- **New**: `DatabaseUUIDEncodingStrategy` is Sendable.
137+
128138
## 6.27.0
129139

130140
Released April 21, 2024

Documentation/CommonTableExpressions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ let rightCTE = ...
251251
let association = LeftRecord.association(
252252
to: rightCTE,
253253
on: { left, right in
254-
left[Column("x")] = right[Column("y")]
254+
left[Column("x")] == right[Column("y")]
255255
})
256256
```
257257

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.27.0'
3+
s.version = '6.28.0'
44

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

GRDB/Core/Cursor.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,56 @@ extension Set {
195195
// database cursors.
196196
try cursor.forEach { insert($0) }
197197
}
198+
199+
/// Returns a new set with the elements of both this set and the
200+
/// given cursor.
201+
///
202+
/// If the set already contains one or more elements that are also in
203+
/// the cursor, the existing members are kept. If the cursor contains
204+
/// multiple instances of equivalent elements, only the first instance
205+
/// is kept.
206+
///
207+
/// - parameter cursor: A cursor of elements.
208+
/// - returns: A new set with the unique elements of this set
209+
/// and `cursor`.
210+
public func union(_ cursor: some Cursor<Element>) throws -> Set<Element> {
211+
var result = self
212+
try result.formUnion(cursor)
213+
return result
214+
}
215+
216+
/// Inserts the elements of the given cursor into the set.
217+
///
218+
/// If the set already contains one or more elements that are also in
219+
/// the cursor, the existing members are kept. If the cursor contains
220+
/// multiple instances of equivalent elements, only the first instance
221+
/// is kept.
222+
///
223+
/// - parameter cursor: A cursor of elements.
224+
public mutating func formUnion(_ cursor: some Cursor<Element>) throws {
225+
while let element = try cursor.next() {
226+
insert(element)
227+
}
228+
}
229+
230+
/// Returns a new set with the elements that are common to both this set
231+
/// and the given cursor.
232+
///
233+
/// - parameter cursor: A cursor of elements.
234+
/// - returns: A new set.
235+
public func intersection(_ cursor: some Cursor<Element>) throws -> Set<Element> {
236+
var result = self
237+
try result.formIntersection(cursor)
238+
return result
239+
}
240+
241+
/// Removes the elements of the set that aren’t also in the
242+
/// given cursor.
243+
///
244+
/// - parameter cursor: A cursor of elements.
245+
public mutating func formIntersection(_ cursor: some Cursor<Element>) throws {
246+
try formIntersection(Set(cursor))
247+
}
198248
}
199249

200250
extension Sequence {

GRDB/QueryInterface/Request/Association/AssociationAggregate.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ extension AssociationToMany {
366366
/// ### Top-Level Functions
367367
///
368368
/// - ``abs(_:)-43n8v``
369+
/// - ``cast(_:as:)-63ttx``
369370
/// - ``length(_:)-9dr2v``
370371
public struct AssociationAggregate<RowDecoder> {
371372
fileprivate let preparation: AssociationAggregatePreparation<RowDecoder>

GRDB/QueryInterface/Request/QueryInterfaceRequest.swift

Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
/// ### Batch Delete
6262
///
6363
/// - ``deleteAll(_:)``
64+
/// - ``deleteAndFetchIds(_:)``
6465
/// - ``deleteAndFetchCursor(_:)``
6566
/// - ``deleteAndFetchAll(_:)``
6667
/// - ``deleteAndFetchSet(_:)``
@@ -528,7 +529,7 @@ extension QueryInterfaceRequest {
528529
///
529530
/// - important: Make sure you check the documentation of the `RETURNING`
530531
/// clause, which describes important limitations and caveats:
531-
/// <https://www.sqlite.org/lang_returning.html>.
532+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
532533
///
533534
/// - parameter db: A database connection.
534535
/// - parameter selection: The returned columns (must not be empty).
@@ -561,7 +562,7 @@ extension QueryInterfaceRequest {
561562
///
562563
/// - important: Make sure you check the documentation of the `RETURNING`
563564
/// clause, which describes important limitations and caveats:
564-
/// <https://www.sqlite.org/lang_returning.html>.
565+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
565566
///
566567
/// - parameter db: A database connection.
567568
/// - returns: A ``RecordCursor`` over the deleted records.
@@ -588,7 +589,7 @@ extension QueryInterfaceRequest {
588589
///
589590
/// - important: Make sure you check the documentation of the `RETURNING`
590591
/// clause, which describes important limitations and caveats:
591-
/// <https://www.sqlite.org/lang_returning.html>.
592+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
592593
///
593594
/// - parameter db: A database connection.
594595
/// - returns: An array of deleted records.
@@ -614,7 +615,7 @@ extension QueryInterfaceRequest {
614615
///
615616
/// - important: Make sure you check the documentation of the `RETURNING`
616617
/// clause, which describes important limitations and caveats:
617-
/// <https://www.sqlite.org/lang_returning.html>.
618+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
618619
///
619620
/// - parameter db: A database connection.
620621
/// - returns: A set of deleted records.
@@ -625,6 +626,41 @@ extension QueryInterfaceRequest {
625626
{
626627
try Set(deleteAndFetchCursor(db))
627628
}
629+
630+
/// Executes a `DELETE RETURNING` statement and returns the set of
631+
/// deleted ids.
632+
///
633+
/// For example:
634+
///
635+
/// ```swift
636+
/// // Fetch the ids of deleted players
637+
/// // DELETE FROM player RETURNING id
638+
/// let request = Player.all()
639+
/// let deletedPlayerIds = try request.deleteAndFetchIds(db)
640+
/// ```
641+
///
642+
/// - important: Make sure you check the documentation of the `RETURNING`
643+
/// clause, which describes important limitations and caveats:
644+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
645+
///
646+
/// - parameter db: A database connection.
647+
/// - returns: A set of deleted ids.
648+
/// - throws: A ``DatabaseError`` whenever an SQLite error occurs.
649+
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) // Identifiable
650+
public func deleteAndFetchIds(_ db: Database)
651+
throws -> Set<RowDecoder.ID>
652+
where RowDecoder: TableRecord & Identifiable,
653+
RowDecoder.ID: Hashable & DatabaseValueConvertible & StatementColumnConvertible
654+
{
655+
let primaryKey = try db.primaryKey(RowDecoder.databaseTableName)
656+
GRDBPrecondition(
657+
primaryKey.columns.count == 1,
658+
"Fetching id requires a single-column primary key in the table \(databaseTableName)")
659+
660+
let statement = try deleteAndFetchStatement(db, selection: [Column(primaryKey.columns[0])])
661+
662+
return try RowDecoder.ID.fetchSet(statement)
663+
}
628664
#else
629665
/// Returns a `DELETE RETURNING` prepared statement.
630666
///
@@ -640,7 +676,7 @@ extension QueryInterfaceRequest {
640676
///
641677
/// - important: Make sure you check the documentation of the `RETURNING`
642678
/// clause, which describes important limitations and caveats:
643-
/// <https://www.sqlite.org/lang_returning.html>.
679+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
644680
///
645681
/// - parameter db: A database connection.
646682
/// - parameter selection: The returned columns (must not be empty).
@@ -674,7 +710,7 @@ extension QueryInterfaceRequest {
674710
///
675711
/// - important: Make sure you check the documentation of the `RETURNING`
676712
/// clause, which describes important limitations and caveats:
677-
/// <https://www.sqlite.org/lang_returning.html>.
713+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
678714
///
679715
/// - parameter db: A database connection.
680716
/// - returns: A ``RecordCursor`` over the deleted records.
@@ -702,7 +738,7 @@ extension QueryInterfaceRequest {
702738
///
703739
/// - important: Make sure you check the documentation of the `RETURNING`
704740
/// clause, which describes important limitations and caveats:
705-
/// <https://www.sqlite.org/lang_returning.html>.
741+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
706742
///
707743
/// - parameter db: A database connection.
708744
/// - returns: An array of deleted records.
@@ -729,7 +765,7 @@ extension QueryInterfaceRequest {
729765
///
730766
/// - important: Make sure you check the documentation of the `RETURNING`
731767
/// clause, which describes important limitations and caveats:
732-
/// <https://www.sqlite.org/lang_returning.html>.
768+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
733769
///
734770
/// - parameter db: A database connection.
735771
/// - returns: A set of deleted records.
@@ -741,6 +777,41 @@ extension QueryInterfaceRequest {
741777
{
742778
try Set(deleteAndFetchCursor(db))
743779
}
780+
781+
/// Executes a `DELETE RETURNING` statement and returns the set of
782+
/// deleted ids.
783+
///
784+
/// For example:
785+
///
786+
/// ```swift
787+
/// // Fetch the ids of deleted players
788+
/// // DELETE FROM player RETURNING id
789+
/// let request = Player.all()
790+
/// let deletedPlayerIds = try request.deleteAndFetchIds(db)
791+
/// ```
792+
///
793+
/// - important: Make sure you check the documentation of the `RETURNING`
794+
/// clause, which describes important limitations and caveats:
795+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
796+
///
797+
/// - parameter db: A database connection.
798+
/// - returns: A set of deleted ids.
799+
/// - throws: A ``DatabaseError`` whenever an SQLite error occurs.
800+
@available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) // SQLite 3.35.0+
801+
public func deleteAndFetchIds(_ db: Database)
802+
throws -> Set<RowDecoder.ID>
803+
where RowDecoder: TableRecord & Identifiable,
804+
RowDecoder.ID: Hashable & DatabaseValueConvertible & StatementColumnConvertible
805+
{
806+
let primaryKey = try db.primaryKey(RowDecoder.databaseTableName)
807+
GRDBPrecondition(
808+
primaryKey.columns.count == 1,
809+
"Fetching id requires a single-column primary key in the table \(databaseTableName)")
810+
811+
let statement = try deleteAndFetchStatement(db, selection: [Column(primaryKey.columns[0])])
812+
813+
return try RowDecoder.ID.fetchSet(statement)
814+
}
744815
#endif
745816
}
746817

@@ -844,7 +915,7 @@ extension QueryInterfaceRequest {
844915
///
845916
/// - important: Make sure you check the documentation of the `RETURNING`
846917
/// clause, which describes important limitations and caveats:
847-
/// <https://www.sqlite.org/lang_returning.html>.
918+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
848919
///
849920
/// - parameter db: A database connection.
850921
/// - parameter conflictResolution: A policy for conflict resolution.
@@ -893,7 +964,7 @@ extension QueryInterfaceRequest {
893964
///
894965
/// - important: Make sure you check the documentation of the `RETURNING`
895966
/// clause, which describes important limitations and caveats:
896-
/// <https://www.sqlite.org/lang_returning.html>.
967+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
897968
///
898969
/// - parameter db: A database connection.
899970
/// - parameter conflictResolution: A policy for conflict resolution.
@@ -930,7 +1001,7 @@ extension QueryInterfaceRequest {
9301001
///
9311002
/// - important: Make sure you check the documentation of the `RETURNING`
9321003
/// clause, which describes important limitations and caveats:
933-
/// <https://www.sqlite.org/lang_returning.html>.
1004+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
9341005
///
9351006
/// - parameter db: A database connection.
9361007
/// - parameter conflictResolution: A policy for conflict resolution.
@@ -962,7 +1033,7 @@ extension QueryInterfaceRequest {
9621033
///
9631034
/// - important: Make sure you check the documentation of the `RETURNING`
9641035
/// clause, which describes important limitations and caveats:
965-
/// <https://www.sqlite.org/lang_returning.html>.
1036+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
9661037
///
9671038
/// - parameter db: A database connection.
9681039
/// - parameter conflictResolution: A policy for conflict resolution.
@@ -996,7 +1067,7 @@ extension QueryInterfaceRequest {
9961067
///
9971068
/// - important: Make sure you check the documentation of the `RETURNING`
9981069
/// clause, which describes important limitations and caveats:
999-
/// <https://www.sqlite.org/lang_returning.html>.
1070+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
10001071
///
10011072
/// - parameter db: A database connection.
10021073
/// - parameter conflictResolution: A policy for conflict resolution.
@@ -1046,7 +1117,7 @@ extension QueryInterfaceRequest {
10461117
///
10471118
/// - important: Make sure you check the documentation of the `RETURNING`
10481119
/// clause, which describes important limitations and caveats:
1049-
/// <https://www.sqlite.org/lang_returning.html>.
1120+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
10501121
///
10511122
/// - parameter db: A database connection.
10521123
/// - parameter conflictResolution: A policy for conflict resolution.
@@ -1084,7 +1155,7 @@ extension QueryInterfaceRequest {
10841155
///
10851156
/// - important: Make sure you check the documentation of the `RETURNING`
10861157
/// clause, which describes important limitations and caveats:
1087-
/// <https://www.sqlite.org/lang_returning.html>.
1158+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
10881159
///
10891160
/// - parameter db: A database connection.
10901161
/// - parameter conflictResolution: A policy for conflict resolution.
@@ -1117,7 +1188,7 @@ extension QueryInterfaceRequest {
11171188
///
11181189
/// - important: Make sure you check the documentation of the `RETURNING`
11191190
/// clause, which describes important limitations and caveats:
1120-
/// <https://www.sqlite.org/lang_returning.html>.
1191+
/// <https://www.sqlite.org/lang_returning.html#limitations_and_caveats>.
11211192
///
11221193
/// - parameter db: A database connection.
11231194
/// - parameter conflictResolution: A policy for conflict resolution.

GRDB/QueryInterface/SQL/SQLExpression.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2167,6 +2167,7 @@ extension SQLExpressible where Self == Column {
21672167
/// - ``average(_:)``
21682168
/// - ``average(_:filter:)``
21692169
/// - ``capitalized``
2170+
/// - ``cast(_:as:)-1dmu3``
21702171
/// - ``count(_:)``
21712172
/// - ``count(distinct:)``
21722173
/// - ``dateTime(_:_:)``

0 commit comments

Comments
 (0)