Skip to content

Commit 6d06754

Browse files
committed
wip
1 parent 5ded480 commit 6d06754

File tree

11 files changed

+115
-54
lines changed

11 files changed

+115
-54
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ comfortable with the library:
155155

156156
* [Getting started](https://swiftpackageindex.com/pointfreeco/swift-structured-queries/~/documentation/structuredqueriescore/gettingstarted)
157157
* [Defining your schema](https://swiftpackageindex.com/pointfreeco/swift-structured-queries/~/documentation/structuredqueriescore/definingyourschema)
158-
* [Primary keyed tables](https://swiftpackageindex.com/pointfreeco/swift-structured-queries/~/documentation/structuredqueriescore/primarykeyedtables)
158+
* [Primary-keyed tables](https://swiftpackageindex.com/pointfreeco/swift-structured-queries/~/documentation/structuredqueriescore/primarykeyedtables)
159159
* [Safe SQL strings](https://swiftpackageindex.com/pointfreeco/swift-structured-queries/~/documentation/structuredqueriescore/safesqlstrings)
160160
* [Query cookbook](https://swiftpackageindex.com/pointfreeco/swift-structured-queries/~/documentation/structuredqueriescore/querycookbook)
161161

Sources/StructuredQueriesCore/Documentation.docc/Articles/DefiningYourSchema.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ that represent those database definitions.
2222
* [RawRepresentable](#RawRepresentable)
2323
* [JSON](#JSON)
2424
* [Tagged identifiers](#Tagged-identifiers)
25-
* [Primary keyed tables](#Primary-keyed-tables)
25+
* [Primary-keyed tables](#Primary-keyed-tables)
2626
* [Grouped columns](#Grouped-columns)
2727
* [Ephemeral columns](#Ephemeral-columns)
2828
* [Generated columns](#Generated-columns)
@@ -321,7 +321,7 @@ struct RemindersList: Identifiable {
321321
}
322322
```
323323

324-
### Primary keyed tables
324+
### Primary-keyed tables
325325

326326
It is possible to let the `@Table` macro know which field of your data type is the primary
327327
key for the table in the database, and doing so unlocks new APIs for inserting, updating, and
@@ -330,6 +330,7 @@ primary key, or you can explicitly specify it with the `primaryKey:` argument of
330330
macro:
331331

332332
```swift
333+
@Table
333334
struct Book {
334335
@Column(primaryKey: true)
335336
let isbn: String
@@ -443,6 +444,7 @@ database. Such properties must have a default value, and can be specified using
443444
macro:
444445
445446
```swift
447+
@Table
446448
struct Book {
447449
@Column(primaryKey: true)
448450
let isbn: String

Sources/StructuredQueriesCore/Documentation.docc/Articles/InsertStatements.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ Or you can populate an entire record from the freshly-inserted database:
293293
### Upserting drafts
294294

295295
At times your application may want to provide the same business logic for creating a new record and
296-
editing an existing one. Your primary keyed table's `Draft` type can be used for these kinds of
296+
editing an existing one. Your primary-keyed table's `Draft` type can be used for these kinds of
297297
flows, and it is possible to create a draft from an existing value using ``TableDraft/init(_:)``:
298298

299299
```swift

Sources/StructuredQueriesCore/Documentation.docc/Articles/PrimaryKeyedTables.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# Primary keyed tables
1+
# Primary-keyed tables
22

33
Learn how tables with a primary key get extra tools when it comes to inserting, updating, and
44
deleting records.
55

66
## Overview
77

8-
A primary keyed table is one that has a column whose value is unique for the entire table. The most
8+
A primary-keyed table is one that has a column whose value is unique for the entire table. The most
99
common example is an "id" column that holds an integer, UUID, or some other kind of identifier.
1010
Typically such columns are also initialized by the database so that when inserting rows into the
1111
table you do not need to specify the primary key. The library provides extra tools that make it
@@ -126,7 +126,7 @@ Or even get back the entire newly inserted row:
126126
}
127127

128128
At times your application may want to provide the same business logic for creating a new record and
129-
editing an existing one. Your primary keyed table's `Draft` type can be used for these kinds of
129+
editing an existing one. Your primary-keyed table's `Draft` type can be used for these kinds of
130130
flows, and it is possible to create a draft from an existing value using ``TableDraft/init(_:)``:
131131

132132
```swift
@@ -141,10 +141,10 @@ ReminderForm(
141141
)
142142
```
143143

144-
### Selects, updates, upserts and deletions
144+
### Selects, updates, upserts, and deletions
145145

146-
Primary keyed tables are also given special APIs for selecting, updating and deleting existing rows
147-
in the table based on their primary key. For example, every primary keyed table is given a special
146+
Primary-keyed tables are also given special APIs for selecting, updating and deleting existing rows
147+
in the table based on their primary key. For example, every primary-keyed table is given a special
148148
``PrimaryKeyedTable/find(_:)`` static method for fetching a record by its primary key:
149149

150150
@Row {

Sources/StructuredQueriesCore/Documentation.docc/Extensions/PrimaryKeyedTable.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ``StructuredQueriesCore/PrimaryKeyedTable``
22

3-
A primary keyed table is one that has a column whose value is unique for the entire table. The most
3+
A primary-keyed table is one that has a column whose value is unique for the entire table. The most
44
common example is an "id" column that holds an integer, UUID, or some other kind of identifier.
55
Typically such columns are also initialized by the database so that when inserting rows into the
66
table you do not need to specify the primary key. The library provides extra tools that make it
@@ -117,7 +117,7 @@ Reminder
117117

118118
### Updates and deletions
119119

120-
Primary keyed tables are also given special APIs for updating and deleting existing rows in the
120+
Primary-keyed tables are also given special APIs for updating and deleting existing rows in the
121121
table based on their primary key. For example, the ``PrimaryKeyedTable/update(_:)`` method
122122
allows one to update all the fields of a row with the corresponding primary key:
123123

Sources/StructuredQueriesCore/Operators.swift

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
extension QueryExpression where QueryValue: _OptionalPromotable {
1+
extension QueryExpression where QueryValue: QueryRepresentable {
22
/// A predicate expression indicating whether two query expressions are equal.
33
///
44
/// ```swift
@@ -77,9 +77,10 @@ extension QueryExpression where QueryValue: _OptionalPromotable {
7777
///
7878
/// - Parameter other: An expression to compare this one to.
7979
/// - Returns: A predicate expression.
80-
public func `is`(
81-
_ other: some QueryExpression<QueryValue._Optionalized>
82-
) -> some QueryExpression<Bool> {
80+
public func `is`<Other: QueryRepresentable>(
81+
_ other: some QueryExpression<Other>
82+
) -> some QueryExpression<Bool>
83+
where QueryValue._Optionalized.Wrapped == Other._Optionalized.Wrapped {
8384
BinaryOperator(lhs: self, operator: "IS", rhs: other)
8485
}
8586

@@ -93,9 +94,10 @@ extension QueryExpression where QueryValue: _OptionalPromotable {
9394
///
9495
/// - Parameter other: An expression to compare this one to.
9596
/// - Returns: A predicate expression.
96-
public func isNot(
97+
public func isNot<Other: QueryRepresentable>(
9798
_ other: some QueryExpression<QueryValue._Optionalized>
98-
) -> some QueryExpression<Bool> {
99+
) -> some QueryExpression<Bool>
100+
where QueryValue._Optionalized.Wrapped == Other._Optionalized.Wrapped {
99101
BinaryOperator(lhs: self, operator: "IS NOT", rhs: other)
100102
}
101103
}
@@ -104,6 +106,34 @@ private func isNull<Value>(_ expression: some QueryExpression<Value>) -> Bool {
104106
(expression as? any _OptionalProtocol).map { $0._wrapped == nil } ?? false
105107
}
106108

109+
extension QueryExpression where QueryValue: QueryRepresentable & QueryExpression {
110+
@_documentation(visibility: private)
111+
public func `is`(
112+
_ other: _Null<QueryValue>
113+
) -> some QueryExpression<Bool> {
114+
BinaryOperator(lhs: self, operator: "IS", rhs: other)
115+
}
116+
117+
@_documentation(visibility: private)
118+
public func isNot(
119+
_ other: _Null<QueryValue>
120+
) -> some QueryExpression<Bool> {
121+
BinaryOperator(lhs: self, operator: "IS NOT", rhs: other)
122+
}
123+
}
124+
125+
public struct _Null<Wrapped: QueryExpression>: QueryExpression {
126+
public typealias QueryValue = Wrapped?
127+
public var queryFragment: QueryFragment {
128+
Wrapped?.none.queryFragment
129+
}
130+
}
131+
132+
extension _Null: ExpressibleByNilLiteral {
133+
public init(nilLiteral: ()) {}
134+
}
135+
136+
// TODO: Remove this when we correctly unwrap `TableColumns` in `join` conditions.
107137
extension QueryExpression where QueryValue: QueryRepresentable & _OptionalProtocol {
108138
@_documentation(visibility: private)
109139
public func eq(_ other: some QueryExpression<QueryValue.Wrapped>) -> some QueryExpression<Bool> {
@@ -140,33 +170,6 @@ extension QueryExpression where QueryValue: QueryRepresentable & _OptionalProtoc
140170
}
141171
}
142172

143-
extension QueryExpression where QueryValue: QueryRepresentable & QueryExpression {
144-
@_documentation(visibility: private)
145-
public func `is`(
146-
_ other: _Null<QueryValue>
147-
) -> some QueryExpression<Bool> {
148-
BinaryOperator(lhs: self, operator: "IS", rhs: other)
149-
}
150-
151-
@_documentation(visibility: private)
152-
public func isNot(
153-
_ other: _Null<QueryValue>
154-
) -> some QueryExpression<Bool> {
155-
BinaryOperator(lhs: self, operator: "IS NOT", rhs: other)
156-
}
157-
}
158-
159-
public struct _Null<Wrapped: QueryExpression>: QueryExpression {
160-
public typealias QueryValue = Wrapped?
161-
public var queryFragment: QueryFragment {
162-
Wrapped?.none.queryFragment
163-
}
164-
}
165-
166-
extension _Null: ExpressibleByNilLiteral {
167-
public init(nilLiteral: ()) {}
168-
}
169-
170173
// NB: This overload is required due to an overload resolution bug of 'Updates[dynamicMember:]'.
171174
@_disfavoredOverload
172175
@_documentation(visibility: private)

Sources/StructuredQueriesCore/PrimaryKeyed.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public protocol TableDraft: Table {
2020

2121
typealias PrimaryKey = PrimaryTable.PrimaryKey
2222

23-
/// Creates a draft from a primary keyed table.
23+
/// Creates a draft from a primary-keyed table.
2424
init(_ primaryTable: PrimaryTable)
2525
}
2626

Sources/StructuredQueriesSQLiteCore/Documentation.docc/Articles/QueryCookbook.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ struct Row {
7575
This allows the query to serialize the associated rows into JSON, which are then deserialized into
7676
a `Row` type. To construct such a query you can use the
7777
``StructuredQueriesCore/PrimaryKeyedTableDefinition/jsonGroupArray(distinct:order:filter:)``
78-
property that is defined on the columns of primary keyed tables:
78+
property that is defined on the columns of primary-keyed tables:
7979

8080
```swift
8181
RemindersList

Tests/StructuredQueriesTests/CommonTableExpressionTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ extension SnapshotTests {
384384
all: true,
385385
Employee
386386
.select { EmployeeReport.Columns(id: $0.id, height: $0.height, name: $0.name) }
387-
.join(EmployeeReport.all) { $0.bossID.eq($1.id) }
387+
.join(EmployeeReport.all) { $0.bossID.is($1.id) }
388388
)
389389
} query: {
390390
EmployeeReport
@@ -397,7 +397,7 @@ extension SnapshotTests {
397397
UNION ALL
398398
SELECT "employees"."id" AS "id", "employees"."height" AS "height", "employees"."name" AS "name"
399399
FROM "employees"
400-
JOIN "employeeReports" ON ("employees"."bossID") = ("employeeReports"."id")
400+
JOIN "employeeReports" ON ("employees"."bossID") IS ("employeeReports"."id")
401401
)
402402
SELECT avg("employeeReports"."height")
403403
FROM "employeeReports"

Tests/StructuredQueriesTests/SelectTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,14 +472,14 @@ extension SnapshotTests {
472472

473473
assertQuery(
474474
Reminder.all
475-
.fullJoin(User.all) { $0.assignedUserID.eq($1.id) }
475+
.fullJoin(User.all) { $0.assignedUserID.is($1.id) }
476476
.select { ($0.title, $1.name) }
477477
.limit(2)
478478
) {
479479
"""
480480
SELECT "reminders"."title", "users"."name"
481481
FROM "reminders"
482-
FULL JOIN "users" ON ("reminders"."assignedUserID") = ("users"."id")
482+
FULL JOIN "users" ON ("reminders"."assignedUserID") IS ("users"."id")
483483
LIMIT 2
484484
"""
485485
} results: {

0 commit comments

Comments
 (0)