Skip to content

Commit 130800e

Browse files
authored
Merge branch 'main' into optional-helpers
2 parents 5ae1c32 + 7109581 commit 130800e

File tree

16 files changed

+698
-98
lines changed

16 files changed

+698
-98
lines changed

Sources/StructuredQueriesCore/AggregateFunctions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ where QueryValue: _OptionalPromotable, QueryValue._Optionalized.Wrapped: Numeric
170170
///
171171
/// ```swift
172172
/// Item.select { $0.price.total() }
173-
/// // SELECT sum("items"."price") FROM "items"
173+
/// // SELECT total("items"."price") FROM "items"
174174
/// ```
175175
///
176176
/// - Parameters:

Sources/StructuredQueriesCore/Internal/Deprecations.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
import Foundation
22

3+
// NB: Deprecated after 0.6.0:
4+
5+
extension QueryFragment {
6+
@available(
7+
*,
8+
deprecated,
9+
message: "Use 'QueryFragment.segments' to build up a SQL string and bindings in a single loop."
10+
)
11+
public var string: String {
12+
segments.reduce(into: "") { string, segment in
13+
switch segment {
14+
case .sql(let sql):
15+
string.append(sql)
16+
case .binding:
17+
string.append("?")
18+
}
19+
}
20+
}
21+
22+
@available(
23+
*,
24+
deprecated,
25+
message: "Use 'QueryFragment.segments' to build up a SQL string and bindings in a single loop."
26+
)
27+
public var bindings: [QueryBinding] {
28+
segments.reduce(into: []) { bindings, segment in
29+
switch segment {
30+
case .sql:
31+
break
32+
case .binding(let binding):
33+
bindings.append(binding)
34+
}
35+
}
36+
}
37+
}
38+
339
// NB: Deprecated after 0.5.1:
440

541
extension Table {

Sources/StructuredQueriesCore/Internal/PrettyPrinting.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,15 @@ extension QueryFragment {
3030
#if DEBUG
3131
guard isTesting else { return self }
3232
var query = self
33-
query.string = " \(query.string.replacingOccurrences(of: "\n", with: "\n "))"
33+
query.segments.insert(.sql(" "), at: 0)
34+
for index in query.segments.indices {
35+
switch query.segments[index] {
36+
case .sql(let sql):
37+
query.segments[index] = .sql(sql.replacingOccurrences(of: "\n", with: "\n "))
38+
case .binding:
39+
continue
40+
}
41+
}
3442
return query
3543
#else
3644
return self

Sources/StructuredQueriesCore/Operators.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ public func == <QueryValue: _OptionalProtocol>(
192192
lhs: any QueryExpression<QueryValue>,
193193
rhs: some QueryExpression<QueryValue.Wrapped>
194194
) -> some QueryExpression<Bool> {
195-
BinaryOperator(lhs: lhs, operator: isNull(lhs) ? "IS" : "=", rhs: rhs)
195+
BinaryOperator(lhs: lhs, operator: "IS", rhs: rhs)
196196
}
197197

198198
// NB: This overload is required due to an overload resolution bug of 'Updates[dynamicMember:]'.
@@ -202,7 +202,7 @@ public func != <QueryValue: _OptionalProtocol>(
202202
lhs: any QueryExpression<QueryValue>,
203203
rhs: some QueryExpression<QueryValue.Wrapped>
204204
) -> some QueryExpression<Bool> {
205-
BinaryOperator(lhs: lhs, operator: isNull(lhs) ? "IS NOT" : "<>", rhs: rhs)
205+
BinaryOperator(lhs: lhs, operator: "IS NOT", rhs: rhs)
206206
}
207207

208208
// NB: This overload is required due to an overload resolution bug of 'Updates[dynamicMember:]'.
@@ -211,7 +211,7 @@ public func == <QueryValue: _OptionalProtocol>(
211211
lhs: any QueryExpression<QueryValue>,
212212
rhs: some QueryExpression<QueryValue>
213213
) -> some QueryExpression<Bool> {
214-
BinaryOperator(lhs: lhs, operator: isNull(lhs) || isNull(rhs) ? "IS" : "=", rhs: rhs)
214+
BinaryOperator(lhs: lhs, operator: "IS", rhs: rhs)
215215
}
216216

217217
// NB: This overload is required due to an overload resolution bug of 'Updates[dynamicMember:]'.
@@ -220,7 +220,7 @@ public func != <QueryValue: _OptionalProtocol>(
220220
lhs: any QueryExpression<QueryValue>,
221221
rhs: some QueryExpression<QueryValue>
222222
) -> some QueryExpression<Bool> {
223-
BinaryOperator(lhs: lhs, operator: isNull(lhs) || isNull(rhs) ? "IS NOT" : "<>", rhs: rhs)
223+
BinaryOperator(lhs: lhs, operator: "IS NOT", rhs: rhs)
224224
}
225225

226226
// NB: This overload is required due to an overload resolution bug of 'Updates[dynamicMember:]'.

Sources/StructuredQueriesCore/PrimaryKeyed.swift

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ public protocol TableDraft: Table {
2222
init(_ primaryTable: PrimaryTable)
2323
}
2424

25+
extension TableDraft {
26+
public static subscript(
27+
dynamicMember keyPath: KeyPath<PrimaryTable.Type, some Statement<PrimaryTable>>
28+
) -> some Statement<Self> {
29+
SQLQueryExpression("\(PrimaryTable.self[keyPath: keyPath])")
30+
}
31+
32+
public static subscript(
33+
dynamicMember keyPath: KeyPath<PrimaryTable.Type, some SelectStatementOf<PrimaryTable>>
34+
) -> SelectOf<Self> {
35+
unsafeBitCast(PrimaryTable.self[keyPath: keyPath].asSelect(), to: SelectOf<Self>.self)
36+
}
37+
38+
public static var all: SelectOf<Self> {
39+
unsafeBitCast(PrimaryTable.all.asSelect(), to: SelectOf<Self>.self)
40+
}
41+
}
42+
2543
/// A type representing a database table's columns.
2644
///
2745
/// Don't conform to this protocol directly. Instead, use the `@Table` and `@Column` macros to
@@ -38,6 +56,14 @@ where QueryValue: PrimaryKeyedTable {
3856
var primaryKey: TableColumn<QueryValue, PrimaryKey> { get }
3957
}
4058

59+
extension TableDefinition where QueryValue: TableDraft {
60+
public subscript<Member>(
61+
dynamicMember keyPath: KeyPath<QueryValue.PrimaryTable.TableColumns, Member>
62+
) -> Member {
63+
QueryValue.PrimaryTable.columns[keyPath: keyPath]
64+
}
65+
}
66+
4167
extension PrimaryKeyedTableDefinition {
4268
/// A query expression representing the number of rows in this table.
4369
///
@@ -60,6 +86,22 @@ extension PrimaryKeyedTable {
6086
}
6187
}
6288

89+
extension TableDraft {
90+
/// A where clause filtered by a primary key.
91+
///
92+
/// - Parameter primaryKey: A primary key identifying a table row.
93+
/// - Returns: A `WHERE` clause.
94+
public static func find(
95+
_ primaryKey: PrimaryTable.TableColumns.PrimaryKey.QueryOutput
96+
) -> Where<Self> {
97+
Self.where { _ in
98+
PrimaryTable.columns.primaryKey.eq(
99+
PrimaryTable.TableColumns.PrimaryKey(queryOutput: primaryKey)
100+
)
101+
}
102+
}
103+
}
104+
63105
extension Where where From: PrimaryKeyedTable {
64106
/// Adds a primary key condition to a where clause.
65107
///
@@ -70,6 +112,40 @@ extension Where where From: PrimaryKeyedTable {
70112
}
71113
}
72114

115+
extension Where where From: TableDraft {
116+
/// Adds a primary key condition to a where clause.
117+
///
118+
/// - Parameter primaryKey: A primary key.
119+
/// - Returns: A where clause with the added primary key.
120+
public func find(_ primaryKey: From.PrimaryTable.TableColumns.PrimaryKey.QueryOutput) -> Self {
121+
self.where { _ in
122+
From.PrimaryTable.columns.primaryKey.eq(
123+
From.PrimaryTable.TableColumns.PrimaryKey(queryOutput: primaryKey)
124+
)
125+
}
126+
}
127+
}
128+
129+
extension Select where From: PrimaryKeyedTable {
130+
/// A select statement filtered by a primary key.
131+
///
132+
/// - Parameter primaryKey: A primary key identifying a table row.
133+
/// - Returns: A select statement filtered by the given key.
134+
public func find(_ primaryKey: From.TableColumns.PrimaryKey.QueryOutput) -> Self {
135+
self.and(From.find(primaryKey))
136+
}
137+
}
138+
139+
extension Select where From: TableDraft {
140+
/// A select statement filtered by a primary key.
141+
///
142+
/// - Parameter primaryKey: A primary key identifying a table row.
143+
/// - Returns: A select statement filtered by the given key.
144+
public func find(_ primaryKey: From.PrimaryTable.TableColumns.PrimaryKey.QueryOutput) -> Self {
145+
self.and(From.find(primaryKey))
146+
}
147+
}
148+
73149
extension Update where From: PrimaryKeyedTable {
74150
/// An update statement filtered by a primary key.
75151
///
@@ -80,6 +156,20 @@ extension Update where From: PrimaryKeyedTable {
80156
}
81157
}
82158

159+
extension Update where From: TableDraft {
160+
/// An update statement filtered by a primary key.
161+
///
162+
/// - Parameter primaryKey: A primary key identifying a table row.
163+
/// - Returns: An update statement filtered by the given key.
164+
public func find(_ primaryKey: From.PrimaryTable.TableColumns.PrimaryKey.QueryOutput) -> Self {
165+
self.where { _ in
166+
From.PrimaryTable.columns.primaryKey.eq(
167+
From.PrimaryTable.TableColumns.PrimaryKey(queryOutput: primaryKey)
168+
)
169+
}
170+
}
171+
}
172+
83173
extension Delete where From: PrimaryKeyedTable {
84174
/// A delete statement filtered by a primary key.
85175
///
@@ -90,12 +180,16 @@ extension Delete where From: PrimaryKeyedTable {
90180
}
91181
}
92182

93-
extension Select where From: PrimaryKeyedTable {
94-
/// A select statement filtered by a primary key.
183+
extension Delete where From: TableDraft {
184+
/// A delete statement filtered by a primary key.
95185
///
96186
/// - Parameter primaryKey: A primary key identifying a table row.
97-
/// - Returns: A select statement filtered by the given key.
98-
public func find(_ primaryKey: From.TableColumns.PrimaryKey.QueryOutput) -> Self {
99-
self.and(From.find(primaryKey))
187+
/// - Returns: A delete statement filtered by the given key.
188+
public func find(_ primaryKey: From.PrimaryTable.TableColumns.PrimaryKey.QueryOutput) -> Self {
189+
self.where { _ in
190+
From.PrimaryTable.columns.primaryKey.eq(
191+
From.PrimaryTable.TableColumns.PrimaryKey(queryOutput: primaryKey)
192+
)
193+
}
100194
}
101195
}

0 commit comments

Comments
 (0)