+138
-92
lines changedFilter options
+138
-92
lines changed Original file line number Diff line number Diff line change
@@ -99,6 +99,7 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one exception:
99
99
- **Breaking**: iOS 11.0+ / macOS 10.13+ / tvOS 11.0+ / watchOS 4.0+ are required.
100
100
- **Breaking**: Removed deprecated methods
101
101
- **Breaking**: The in-memory `DatabaseQueue()` initializer can now throw errors.
102
+
- **Breaking**: The `selectID()` method is replaced with `selectPrimaryKey(as:)`.
102
103
- **New**: Request protocols and cursors now define primary associated types, enabled by [SE-0346](https://github.com/apple/swift-evolution/blob/main/proposals/0346-light-weight-same-type-syntax.md).
103
104
104
105
## 5.26.0
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ class AppDatabaseTests: XCTestCase {
61
61
_ = try Player(id: nil, name: "Barbara", score: 200).inserted(db)
62
62
_ = try Player(id: nil, name: "Craig", score: 150).inserted(db)
63
63
_ = try Player(id: nil, name: "David", score: 120).inserted(db)
64
-
return try Player.selectID().fetchAll(db)
64
+
return try Player.selectPrimaryKey().fetchAll(db)
65
65
}
66
66
67
67
// When we delete two players
Original file line number Diff line number Diff line change
@@ -50,3 +50,13 @@ The `Cursor` protocol has also gained a primary associated type (the type of its
50
50
-let dbQueue = DatabaseQueue()
51
51
+let dbQueue = try DatabaseQueue()
52
52
```
53
+
54
+
- The `selectID()` method is removed. You can provide your own implementation, based on the new `selectPrimaryKey(as:)` method:
55
+
56
+
```swift
57
+
extension QueryInterfaceRequest<Player> {
58
+
func selectID() -> QueryInterfaceRequest<Int64> {
59
+
selectPrimaryKey()
60
+
}
61
+
}
62
+
```
Original file line number Diff line number Diff line change
@@ -371,13 +371,13 @@ Extensions to the `DerivableRequest` protocol can not change the type of request
371
371
// Author requests ~~~~~~~~~~~~~~~~~~~~~~~~~~
372
372
extension QueryInterfaceRequest where RowDecoder == Author {
373
373
// Selects author ids
374
-
func id() -> QueryInterfaceRequest<Int64> {
375
-
select(Author.Columns.id)
374
+
func selectId() -> QueryInterfaceRequest<Int64> {
375
+
selectPrimaryKey(as: Int64.self)
376
376
}
377
377
}
378
378
379
379
// IDs of French authors
380
-
let ids: [Int64] = try Author.all().filter(country: "France").id().fetchAll(db)
380
+
let ids: [Int64] = try Author.all().filter(country: "France").selectId().fetchAll(db)
381
381
```
382
382
383
383
## Compose Records
Original file line number Diff line number Diff line change
@@ -52,12 +52,30 @@ typealias FastNullableDatabaseValueCursor<T: DatabaseValueConvertible & Statemen
52
52
@available(*, unavailable, message: "NullableDatabaseValueCursor<T> has been replaced with DatabaseValueCursor<T?>")
53
53
typealias NullableDatabaseValueCursor<T: DatabaseValueConvertible> = DatabaseValueCursor<T?>
54
54
55
+
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6, *)
56
+
extension QueryInterfaceRequest where RowDecoder: Identifiable, RowDecoder.ID: DatabaseValueConvertible {
57
+
@available(*, unavailable, message: "selectID() has been removed. You may use selectPrimaryKey(as:) instead.")
58
+
public func selectID() -> QueryInterfaceRequest<RowDecoder.ID> { preconditionFailure() }
59
+
}
60
+
55
61
@available(*, unavailable, renamed: "Statement")
56
62
public typealias SelectStatement = Statement
57
63
58
64
@available(*, unavailable, renamed: "SQLExpression.AssociativeBinaryOperator")
59
65
public typealias SQLAssociativeBinaryOperator = SQLExpression.AssociativeBinaryOperator
60
66
67
+
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6, *)
68
+
extension Table where RowDecoder: Identifiable, RowDecoder.ID: DatabaseValueConvertible {
69
+
@available(*, unavailable, message: "selectID() has been removed. You may use selectPrimaryKey(as:) instead.")
70
+
public func selectID() -> QueryInterfaceRequest<RowDecoder.ID> { preconditionFailure() }
71
+
}
72
+
73
+
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6, *)
74
+
extension TableRecord where Self: Identifiable, ID: DatabaseValueConvertible {
75
+
@available(*, unavailable, message: "selectID() has been removed. You may use selectPrimaryKey(as:) instead.")
76
+
public static func selectID() -> QueryInterfaceRequest<ID> { preconditionFailure() }
77
+
}
78
+
61
79
@available(*, unavailable, renamed: "Statement")
62
80
public typealias UpdateStatement = Statement
63
81
Original file line number Diff line number Diff line change
@@ -149,6 +149,30 @@ extension QueryInterfaceRequest: SelectionRequest {
149
149
select(sqlLiteral, as: type)
150
150
}
151
151
152
+
/// Creates a request which selects the primary key.
153
+
///
154
+
/// All primary keys are supported:
155
+
///
156
+
/// // SELECT id FROM player WHERE ...
157
+
/// let request = try Player.filter(...).selectPrimaryKey(as: Int64.self)
158
+
///
159
+
/// // SELECT code FROM country WHERE ...
160
+
/// let request = try Country.filter(...).selectPrimaryKey(as: String.self)
161
+
///
162
+
/// // SELECT citizenId, countryCode FROM citizenship WHERE ...
163
+
/// let request = try Citizenship.filter(...).selectPrimaryKey(as: Row.self)
164
+
public func selectPrimaryKey<PrimaryKey>(as type: PrimaryKey.Type = PrimaryKey.self)
165
+
-> QueryInterfaceRequest<PrimaryKey>
166
+
{
167
+
with { request in
168
+
let tableName = request.relation.source.tableName
169
+
request.relation = request.relation.select { db in
170
+
try db.primaryKey(tableName).columns.map { Column($0).sqlSelection }
171
+
}
172
+
}
173
+
.asRequest(of: PrimaryKey.self)
174
+
}
175
+
152
176
/// Creates a request which appends *selection promise*.
153
177
///
154
178
/// // SELECT id, email, name FROM player
@@ -165,26 +189,6 @@ extension QueryInterfaceRequest: SelectionRequest {
165
189
}
166
190
}
167
191
168
-
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6, *)
169
-
extension QueryInterfaceRequest
170
-
where RowDecoder: Identifiable,
171
-
RowDecoder.ID: DatabaseValueConvertible
172
-
{
173
-
/// Creates a request which selects the primary key.
174
-
///
175
-
/// // SELECT id FROM player WHERE ...
176
-
/// let request = try Player.filter(...).selectID()
177
-
public func selectID() -> QueryInterfaceRequest<RowDecoder.ID> {
178
-
select { db in
179
-
let primaryKey = try db.primaryKey(self.databaseTableName)
180
-
GRDBPrecondition(
181
-
primaryKey.columns.count == 1,
182
-
"selectID requires a single-column primary key in the table \(self.databaseTableName)")
183
-
return [Column(primaryKey.columns[0])]
184
-
}.asRequest(of: RowDecoder.ID.self)
185
-
}
186
-
}
187
-
188
192
extension QueryInterfaceRequest: FilteredRequest {
189
193
/// Creates a request with the provided *predicate promise* added to the
190
194
/// eventual set of already applied predicates.
Original file line number Diff line number Diff line change
@@ -393,14 +393,28 @@ extension Table where RowDecoder: Identifiable, RowDecoder.ID: DatabaseValueConv
393
393
public func filter(ids: some Collection<RowDecoder.ID>) -> QueryInterfaceRequest<RowDecoder> {
394
394
all().filter(ids: ids)
395
395
}
396
-
396
+
}
397
+
398
+
extension Table {
397
399
/// Creates a request which selects the primary key.
398
400
///
401
+
/// All primary keys are supported:
402
+
///
399
403
/// // SELECT id FROM player
400
404
/// let table = Table("player")
401
-
/// let request = try table.selectID()
402
-
public func selectID() -> QueryInterfaceRequest<RowDecoder.ID> {
403
-
all().selectID()
405
+
/// let request = try table.selectPrimaryKey(as: Int64.self)
406
+
///
407
+
/// // SELECT code FROM country
408
+
/// let table = Table("country")
409
+
/// let request = try table.selectPrimaryKey(as: String.self)
410
+
///
411
+
/// // SELECT citizenId, countryCode FROM citizenship
412
+
/// let table = Table("citizenship")
413
+
/// let request = try table.selectPrimaryKey(as: Row.self)
414
+
public func selectPrimaryKey<PrimaryKey>(as type: PrimaryKey.Type = PrimaryKey.self)
415
+
-> QueryInterfaceRequest<PrimaryKey>
416
+
{
417
+
all().selectPrimaryKey(as: type)
404
418
}
405
419
}
406
420
Original file line number Diff line number Diff line change
@@ -130,6 +130,24 @@ extension TableRecord {
130
130
all().select(sqlLiteral, as: type)
131
131
}
132
132
133
+
/// Creates a request which selects the primary key.
134
+
///
135
+
/// All primary keys are supported:
136
+
///
137
+
/// // SELECT id FROM player
138
+
/// let request = try Player.selectPrimaryKey(as: Int64.self)
139
+
///
140
+
/// // SELECT code FROM country
141
+
/// let request = try Country.selectPrimaryKey(as: String.self)
142
+
///
143
+
/// // SELECT citizenId, countryCode FROM citizenship
144
+
/// let request = try Citizenship.selectPrimaryKey(as: Row.self)
145
+
public static func selectPrimaryKey<PrimaryKey>(as type: PrimaryKey.Type = PrimaryKey.self)
146
+
-> QueryInterfaceRequest<PrimaryKey>
147
+
{
148
+
all().selectPrimaryKey(as: type)
149
+
}
150
+
133
151
/// Creates a request which appends *selection*.
134
152
///
135
153
/// // SELECT id, email, name FROM player
@@ -364,12 +382,4 @@ extension TableRecord where Self: Identifiable, ID: DatabaseValueConvertible {
364
382
public static func filter(ids: some Collection<ID>) -> QueryInterfaceRequest<Self> {
365
383
all().filter(ids: ids)
366
384
}
367
-
368
-
/// Creates a request which selects the primary key.
369
-
///
370
-
/// // SELECT id FROM player
371
-
/// let request = try Player.selectID()
372
-
public static func selectID() -> QueryInterfaceRequest<ID> {
373
-
all().selectID()
374
-
}
375
385
}
Original file line number Diff line number Diff line change
@@ -3016,9 +3016,6 @@ let players = try Player.fetchSet(db, ids: [1, 2, 3])
3016
3016
let request = Player.filter(id: 1)
3017
3017
let request = Player.filter(ids: [1, 2, 3])
3018
3018
3019
-
let ids = try Player.selectID().fetchAll(db)
3020
-
let ids = try Player.filter(...).selectID().fetchSet(db)
3021
-
3022
3019
try Player.deleteOne(db, id: 1)
3023
3020
try Player.deleteAll(db, ids: [1, 2, 3])
3024
3021
```
@@ -4076,7 +4073,7 @@ This is the list of record methods, along with their required protocols. The [Re
4076
4073
| `Type.none()` | [TableRecord] | <a href="#list-of-record-methods-2">²</a> |
4077
4074
| `Type.select(...)` | [TableRecord] | <a href="#list-of-record-methods-2">²</a> |
4078
4075
| `Type.select(..., as:...)` | [TableRecord] | <a href="#list-of-record-methods-2">²</a> |
4079
-
| `Type.selectID()` | [TableRecord] & Identifiable | [*](#identifiable-records) |
4076
+
| `Type.selectPrimaryKey(as:...)` | [TableRecord] | <a href="#list-of-record-methods-2">²</a> |
4080
4077
| `Type.annotated(with:...)` | [TableRecord] | <a href="#list-of-record-methods-2">²</a> |
4081
4078
| `Type.filter(...)` | [TableRecord] | <a href="#list-of-record-methods-2">²</a> |
4082
4079
| `Type.filter(id:)` | [TableRecord] & Identifiable | [*](#identifiable-records) |
@@ -4491,16 +4488,6 @@ You can now build requests with the following methods: `all`, `none`, `select`,
4491
4488
Player.select(nameColumn, as: String.self)
4492
4489
```
4493
4490
4494
-
- `selectID()` is available on [Identifiable Records]. It supports all tables that have a single-column primary key:
4495
-
4496
-
```swift
4497
-
// SELECT id FROM player
4498
-
Player.selectID()
4499
-
4500
-
// SELECT id FROM player WHERE name IS NOT NULL
4501
-
Player.filter(nameColumn != nil).selectID()
4502
-
```
4503
-
4504
4491
- `annotated(with: expression...)` extends the selection.
4505
4492
4506
4493
```swift
@@ -4677,6 +4664,19 @@ You can now build requests with the following methods: `all`, `none`, `select`,
4677
4664
4678
4665
- Other requests that involve the primary key:
4679
4666
4667
+
- `selectPrimaryKey(as:)` selects the primary key.
4668
+
4669
+
```swift
4670
+
// SELECT id FROM player
4671
+
Player.selectPrimaryKey(as: Int64.self) // QueryInterfaceRequest<Int64>
4672
+
4673
+
// SELECT code FROM country
4674
+
Country.selectPrimaryKey(as: String.self) // QueryInterfaceRequest<String>
4675
+
4676
+
// SELECT citizenId, countryCode FROM citizenship
4677
+
Citizenship.selectPrimaryKey(as: Row.self) // QueryInterfaceRequest<Row>
4678
+
```
4679
+
4680
4680
- `orderByPrimaryKey()` sorts by primary key.
4681
4681
4682
4682
```swift
Original file line number Diff line number Diff line change
@@ -747,33 +747,29 @@ class RecordMinimalNonOptionalPrimaryKeySingleTests: GRDBTestCase {
747
747
}
748
748
}
749
749
750
-
// MARK: Select ID
750
+
// MARK: Select PrimaryKey
751
751
752
-
func test_static_selectID() throws {
753
-
guard #available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6, *) else {
754
-
throw XCTSkip("Identifiable not available")
755
-
}
756
-
752
+
func test_static_selectPrimaryKey() throws {
757
753
let dbQueue = try makeDatabaseQueue()
758
754
try dbQueue.inDatabase { db in
759
755
let record = MinimalNonOptionalPrimaryKeySingle(id: "theUUID")
760
756
try record.insert(db)
761
-
let ids = try MinimalSingle.selectID().fetchAll(db)
757
+
let ids: [String] = try MinimalSingle.selectPrimaryKey().fetchAll(db)
762
758
XCTAssertEqual(ids, ["theUUID"])
759
+
let rows = try MinimalSingle.selectPrimaryKey(as: Row.self).fetchAll(db)
760
+
XCTAssertEqual(rows, [["id": "theUUID"]])
763
761
}
764
762
}
765
763
766
-
func test_request_selectID() throws {
767
-
guard #available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6, *) else {
768
-
throw XCTSkip("Identifiable not available")
769
-
}
770
-
764
+
func test_request_selectPrimaryKey() throws {
771
765
let dbQueue = try makeDatabaseQueue()
772
766
try dbQueue.inDatabase { db in
773
767
let record = MinimalNonOptionalPrimaryKeySingle(id: "theUUID")
774
768
try record.insert(db)
775
-
let ids = try MinimalSingle.all().selectID().fetchAll(db)
769
+
let ids: [String] = try MinimalSingle.all().selectPrimaryKey().fetchAll(db)
776
770
XCTAssertEqual(ids, ["theUUID"])
771
+
let rows = try MinimalSingle.all().selectPrimaryKey(as: Row.self).fetchAll(db)
772
+
XCTAssertEqual(rows, [["id": "theUUID"]])
777
773
}
778
774
}
779
775
}
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4