Skip to content

Commit 20e331c

Browse files
committed
Reintroduce excluded to upsert clauses
The original implementation in #95 had to be reverted due to issues with nested dynamic member lookup. This PR makes a breaking change to the `Updates` type, instead, to introduce this surface area.
1 parent efd928f commit 20e331c

File tree

7 files changed

+50
-32
lines changed

7 files changed

+50
-32
lines changed

Sources/StructuredQueriesCore/Internal/Deprecations.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extension Table {
4545
public static func insert(
4646
or conflictResolution: ConflictResolution? = nil,
4747
_ row: Self,
48-
onConflict doUpdate: ((inout Updates<Self>) -> Void)? = nil
48+
onConflict doUpdate: ((inout Updates<Self, Excluded>) -> Void)? = nil
4949
) -> InsertOf<Self> {
5050
insert(or: conflictResolution, [row], onConflict: doUpdate)
5151
}
@@ -56,7 +56,7 @@ extension Table {
5656
public static func insert(
5757
or conflictResolution: ConflictResolution? = nil,
5858
_ rows: [Self],
59-
onConflict doUpdate: ((inout Updates<Self>) -> Void)? = nil
59+
onConflict doUpdate: ((inout Updates<Self, Excluded>) -> Void)? = nil
6060
) -> InsertOf<Self> {
6161
insert(or: conflictResolution, values: { rows }, onConflict: doUpdate)
6262
}
@@ -66,7 +66,7 @@ extension Table {
6666
or conflictResolution: ConflictResolution? = nil,
6767
_ columns: (TableColumns) -> TableColumns = { $0 },
6868
@InsertValuesBuilder<Self> values: () -> [Self],
69-
onConflict updates: ((inout Updates<Self>) -> Void)?
69+
onConflict updates: ((inout Updates<Self, Excluded>) -> Void)?
7070
) -> InsertOf<Self> {
7171
insert(or: conflictResolution, columns, values: values, onConflictDoUpdate: updates)
7272
}
@@ -77,7 +77,7 @@ extension Table {
7777
_ columns: (TableColumns) -> (TableColumn<Self, V1>, repeat TableColumn<Self, each V2>),
7878
@InsertValuesBuilder<(V1.QueryOutput, repeat (each V2).QueryOutput)>
7979
values: () -> [(V1.QueryOutput, repeat (each V2).QueryOutput)],
80-
onConflict updates: ((inout Updates<Self>) -> Void)?
80+
onConflict updates: ((inout Updates<Self, Excluded>) -> Void)?
8181
) -> InsertOf<Self> {
8282
insert(or: conflictResolution, columns, values: values, onConflictDoUpdate: updates)
8383
}
@@ -89,7 +89,7 @@ extension Table {
8989
or conflictResolution: ConflictResolution? = nil,
9090
_ columns: (TableColumns) -> (TableColumn<Self, V1>, repeat TableColumn<Self, each V2>),
9191
select selection: () -> Select<(V1, repeat each V2), From, Joins>,
92-
onConflict updates: ((inout Updates<Self>) -> Void)?
92+
onConflict updates: ((inout Updates<Self, Excluded>) -> Void)?
9393
) -> InsertOf<Self> {
9494
insert(or: conflictResolution, columns, select: selection, onConflictDoUpdate: updates)
9595
}
@@ -102,7 +102,7 @@ extension PrimaryKeyedTable {
102102
public static func insert(
103103
or conflictResolution: ConflictResolution? = nil,
104104
_ row: Draft,
105-
onConflict updates: ((inout Updates<Self>) -> Void)? = nil
105+
onConflict updates: ((inout Updates<Self, Excluded>) -> Void)? = nil
106106
) -> InsertOf<Self> {
107107
insert(or: conflictResolution, values: { row }, onConflictDoUpdate: updates)
108108
}
@@ -113,7 +113,7 @@ extension PrimaryKeyedTable {
113113
public static func insert(
114114
or conflictResolution: ConflictResolution? = nil,
115115
_ rows: [Draft],
116-
onConflict updates: ((inout Updates<Self>) -> Void)? = nil
116+
onConflict updates: ((inout Updates<Self, Excluded>) -> Void)? = nil
117117
) -> InsertOf<Self> {
118118
insert(or: conflictResolution, values: { rows }, onConflictDoUpdate: updates)
119119
}

Sources/StructuredQueriesCore/Statements/Insert.swift

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import IssueReporting
22

33
extension Table {
4+
/// Columns referencing the value that would have been inserted in an
5+
/// [insert statement](<doc:InsertStatements>) had there been no conflict.
6+
public typealias Excluded = TableAlias<Self, _ExcludedName>.TableColumns
7+
48
/// An insert statement for one or more table rows.
59
///
610
/// This function can be used to create an insert statement from a ``Table`` value.
@@ -54,7 +58,7 @@ extension Table {
5458
or conflictResolution: ConflictResolution? = nil,
5559
_ columns: (TableColumns) -> TableColumns = { $0 },
5660
@InsertValuesBuilder<Self> values: () -> [Self],
57-
onConflictDoUpdate updates: ((inout Updates<Self>) -> Void)? = nil,
61+
onConflictDoUpdate updates: ((inout Updates<Self, Excluded>) -> Void)? = nil,
5862
@QueryFragmentBuilder<Bool>
5963
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
6064
) -> InsertOf<Self> {
@@ -89,7 +93,7 @@ extension Table {
8993
),
9094
@QueryFragmentBuilder<Bool>
9195
where targetFilter: (TableColumns) -> [QueryFragment] = { _ in [] },
92-
doUpdate updates: (inout Updates<Self>) -> Void = { _ in },
96+
doUpdate updates: (inout Updates<Self, Excluded>) -> Void = { _ in },
9397
@QueryFragmentBuilder<Bool>
9498
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
9599
) -> InsertOf<Self> {
@@ -111,7 +115,7 @@ extension Table {
111115
onConflict conflictTargets: (TableColumns) -> (repeat TableColumn<Self, each ConflictTarget>)?,
112116
@QueryFragmentBuilder<Bool>
113117
where targetFilter: (TableColumns) -> [QueryFragment] = { _ in [] },
114-
doUpdate updates: ((inout Updates<Self>) -> Void)?,
118+
doUpdate updates: ((inout Updates<Self, Excluded>) -> Void)?,
115119
@QueryFragmentBuilder<Bool>
116120
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
117121
) -> InsertOf<Self> {
@@ -197,7 +201,7 @@ extension Table {
197201
_ columns: (TableColumns) -> (TableColumn<Self, V1>, repeat TableColumn<Self, each V2>),
198202
@InsertValuesBuilder<(V1.QueryOutput, repeat (each V2).QueryOutput)>
199203
values: () -> [(V1.QueryOutput, repeat (each V2).QueryOutput)],
200-
onConflictDoUpdate updates: ((inout Updates<Self>) -> Void)? = nil,
204+
onConflictDoUpdate updates: ((inout Updates<Self, Excluded>) -> Void)? = nil,
201205
@QueryFragmentBuilder<Bool>
202206
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
203207
) -> InsertOf<Self> {
@@ -234,7 +238,7 @@ extension Table {
234238
),
235239
@QueryFragmentBuilder<Bool>
236240
where targetFilter: (TableColumns) -> [QueryFragment] = { _ in [] },
237-
doUpdate updates: (inout Updates<Self>) -> Void = { _ in },
241+
doUpdate updates: (inout Updates<Self, Excluded>) -> Void = { _ in },
238242
@QueryFragmentBuilder<Bool>
239243
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
240244
) -> InsertOf<Self> {
@@ -259,7 +263,7 @@ extension Table {
259263
onConflict conflictTargets: (TableColumns) -> (repeat TableColumn<Self, each ConflictTarget>)?,
260264
@QueryFragmentBuilder<Bool>
261265
where targetFilter: (TableColumns) -> [QueryFragment] = { _ in [] },
262-
doUpdate updates: ((inout Updates<Self>) -> Void)?,
266+
doUpdate updates: ((inout Updates<Self, Excluded>) -> Void)?,
263267
@QueryFragmentBuilder<Bool>
264268
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
265269
) -> InsertOf<Self> {
@@ -306,7 +310,7 @@ extension Table {
306310
or conflictResolution: ConflictResolution? = nil,
307311
_ columns: (TableColumns) -> (TableColumn<Self, V1>, repeat TableColumn<Self, each V2>),
308312
select selection: () -> some PartialSelectStatement<(V1, repeat each V2)>,
309-
onConflictDoUpdate updates: ((inout Updates<Self>) -> Void)? = nil,
313+
onConflictDoUpdate updates: ((inout Updates<Self, Excluded>) -> Void)? = nil,
310314
@QueryFragmentBuilder<Bool>
311315
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
312316
) -> InsertOf<Self> {
@@ -350,7 +354,7 @@ extension Table {
350354
),
351355
@QueryFragmentBuilder<Bool>
352356
where targetFilter: (TableColumns) -> [QueryFragment] = { _ in [] },
353-
doUpdate updates: (inout Updates<Self>) -> Void = { _ in },
357+
doUpdate updates: (inout Updates<Self, Excluded>) -> Void = { _ in },
354358
@QueryFragmentBuilder<Bool>
355359
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
356360
) -> InsertOf<Self> {
@@ -377,7 +381,7 @@ extension Table {
377381
onConflict conflictTargets: (TableColumns) -> (repeat TableColumn<Self, each ConflictTarget>)?,
378382
@QueryFragmentBuilder<Bool>
379383
where targetFilter: (TableColumns) -> [QueryFragment] = { _ in [] },
380-
doUpdate updates: ((inout Updates<Self>) -> Void)?,
384+
doUpdate updates: ((inout Updates<Self, Excluded>) -> Void)?,
381385
@QueryFragmentBuilder<Bool>
382386
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
383387
) -> InsertOf<Self> {
@@ -428,7 +432,7 @@ extension Table {
428432
onConflict conflictTargets: (TableColumns) -> (repeat TableColumn<Self, each ConflictTarget>)?,
429433
@QueryFragmentBuilder<Bool>
430434
where targetFilter: (TableColumns) -> [QueryFragment] = { _ in [] },
431-
doUpdate updates: ((inout Updates<Self>) -> Void)?,
435+
doUpdate updates: ((inout Updates<Self, Excluded>) -> Void)?,
432436
@QueryFragmentBuilder<Bool>
433437
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
434438
) -> InsertOf<Self> {
@@ -444,7 +448,7 @@ extension Table {
444448
conflictTargetColumnNames: conflictTargetColumnNames,
445449
conflictTargetFilter: targetFilter(Self.columns),
446450
values: values,
447-
updates: updates.map { Updates($0) },
451+
updates: updates.map { Updates($0, excluded: Excluded.QueryValue.columns) },
448452
updateFilter: updateFilter(Self.columns),
449453
returning: []
450454
)
@@ -468,7 +472,7 @@ extension PrimaryKeyedTable {
468472
or conflictResolution: ConflictResolution? = nil,
469473
_ columns: (Draft.TableColumns) -> Draft.TableColumns = { $0 },
470474
@InsertValuesBuilder<Draft> values: () -> [Draft],
471-
onConflictDoUpdate updates: ((inout Updates<Self>) -> Void)? = nil,
475+
onConflictDoUpdate updates: ((inout Updates<Self, Excluded>) -> Void)? = nil,
472476
@QueryFragmentBuilder<Bool>
473477
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
474478
) -> InsertOf<Self> {
@@ -504,7 +508,7 @@ extension PrimaryKeyedTable {
504508
),
505509
@QueryFragmentBuilder<Bool>
506510
where targetFilter: (TableColumns) -> [QueryFragment] = { _ in [] },
507-
doUpdate updates: (inout Updates<Self>) -> Void = { _ in },
511+
doUpdate updates: (inout Updates<Self, Excluded>) -> Void = { _ in },
508512
@QueryFragmentBuilder<Bool>
509513
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
510514
) -> InsertOf<Self> {
@@ -557,7 +561,7 @@ extension PrimaryKeyedTable {
557561
onConflict conflictTargets: (TableColumns) -> (repeat TableColumn<Self, each ConflictTarget>)?,
558562
@QueryFragmentBuilder<Bool>
559563
where targetFilter: (TableColumns) -> [QueryFragment] = { _ in [] },
560-
doUpdate updates: ((inout Updates<Self>) -> Void)?,
564+
doUpdate updates: ((inout Updates<Self, Excluded>) -> Void)?,
561565
@QueryFragmentBuilder<Bool>
562566
where updateFilter: (TableColumns) -> [QueryFragment] = { _ in [] }
563567
) -> InsertOf<Self> {
@@ -603,7 +607,7 @@ public struct Insert<Into: Table, Returning> {
603607
var conflictTargetColumnNames: [String]
604608
var conflictTargetFilter: [QueryFragment]
605609
fileprivate var values: InsertValues
606-
var updates: Updates<Into>?
610+
var updates: Updates<Into, Into.Excluded>?
607611
var updateFilter: [QueryFragment]
608612
var returning: [QueryFragment]
609613

@@ -613,7 +617,7 @@ public struct Insert<Into: Table, Returning> {
613617
conflictTargetColumnNames: [String],
614618
conflictTargetFilter: [QueryFragment],
615619
values: InsertValues,
616-
updates: Updates<Into>?,
620+
updates: Updates<Into, Into.Excluded>?,
617621
updateFilter: [QueryFragment],
618622
returning: [QueryFragment]
619623
) {
@@ -806,3 +810,7 @@ public enum InsertValuesBuilder<Value> {
806810
accumulated + next
807811
}
808812
}
813+
814+
public struct _ExcludedName: AliasName {
815+
public static var aliasName: String { "excluded" }
816+
}

Sources/StructuredQueriesCore/Statements/Update.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ extension Table {
3535
/// - Returns: An update statement.
3636
public static func update(
3737
or conflictResolution: ConflictResolution? = nil,
38-
set updates: (inout Updates<Self>) -> Void
38+
set updates: (inout UpdatesOf<Self>) -> Void
3939
) -> UpdateOf<Self> {
4040
Update(conflictResolution: conflictResolution, updates: Updates(updates))
4141
}
@@ -92,7 +92,7 @@ extension PrimaryKeyedTable {
9292
/// To learn more, see <doc:UpdateStatements>.
9393
public struct Update<From: Table, Returning> {
9494
var conflictResolution: ConflictResolution?
95-
var updates: Updates<From>
95+
var updates: UpdatesOf<From>
9696
var `where`: [QueryFragment] = []
9797
var returning: [QueryFragment] = []
9898

Sources/StructuredQueriesCore/Statements/Where.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ extension Where: SelectStatement {
481481
/// - Returns: An update statement.
482482
public func update(
483483
or conflictResolution: ConflictResolution? = nil,
484-
set updates: (inout Updates<From>) -> Void
484+
set updates: (inout UpdatesOf<From>) -> Void
485485
) -> UpdateOf<From> {
486486
Update(
487487
conflictResolution: conflictResolution,

Sources/StructuredQueriesCore/Triggers.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ extension Table {
9595
public static func createTemporaryTrigger(
9696
_ name: String? = nil,
9797
ifNotExists: Bool = false,
98-
afterUpdateTouch updates: (inout Updates<Self>) -> Void,
98+
afterUpdateTouch updates: (inout UpdatesOf<Self>) -> Void,
9999
fileID: StaticString = #fileID,
100100
line: UInt = #line,
101101
column: UInt = #column
@@ -173,7 +173,7 @@ extension Table {
173173
public static func createTemporaryTrigger(
174174
_ name: String? = nil,
175175
ifNotExists: Bool = false,
176-
afterInsertTouch updates: (inout Updates<Self>) -> Void,
176+
afterInsertTouch updates: (inout UpdatesOf<Self>) -> Void,
177177
fileID: StaticString = #fileID,
178178
line: UInt = #line,
179179
column: UInt = #column

Sources/StructuredQueriesCore/Updates.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@
55
///
66
/// To learn more, see <doc:UpdateStatements>.
77
@dynamicMemberLookup
8-
public struct Updates<Base: Table> {
8+
public struct Updates<Base: Table, Excluded: Sendable> {
9+
/// The value that would have been inserted in an [insert statement](<doc:InsertStatements>) had
10+
/// there been no conflict.
11+
public let excluded: Excluded
12+
913
private var updates: [(String, QueryFragment)] = []
1014

11-
init(_ body: (inout Self) -> Void) {
15+
init(
16+
_ body: (inout Self) -> Void,
17+
excluded: Excluded = ()
18+
) {
19+
self.excluded = excluded
1220
body(&self)
1321
}
1422

@@ -52,6 +60,8 @@ public struct Updates<Base: Table> {
5260
}
5361
}
5462

63+
public typealias UpdatesOf<Base: Table> = Updates<Base, ()>
64+
5565
extension Updates: QueryExpression {
5666
public typealias QueryValue = Never
5767

Tests/StructuredQueriesTests/InsertTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ extension SnapshotTests {
585585
} where: {
586586
!$0.isCompleted
587587
} doUpdate: {
588-
$0.isCompleted = true
588+
$0.isCompleted = $0.excluded.isCompleted
589589
} where: {
590590
$0.isFlagged
591591
}
@@ -597,7 +597,7 @@ extension SnapshotTests {
597597
(NULL, NULL, NULL, 0, 0, '', NULL, 1, '', '2040-02-14 23:31:30.000')
598598
ON CONFLICT ("id")
599599
WHERE NOT ("reminders"."isCompleted")
600-
DO UPDATE SET "isCompleted" = 1
600+
DO UPDATE SET "isCompleted" = "excluded"."isCompleted"
601601
WHERE "reminders"."isFlagged"
602602
"""
603603
}

0 commit comments

Comments
 (0)