Skip to content

Commit b7e4966

Browse files
authored
Reintroduce excluded to upsert clauses (pointfreeco#98)
* Reintroduce `excluded` to upsert clauses The original implementation in pointfreeco#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. * wip * wip * An alternate implementation of `excluded` conflict resolution (pointfreeco#100) * wip
1 parent a70aadb commit b7e4966

File tree

3 files changed

+383
-32
lines changed

3 files changed

+383
-32
lines changed

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

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,9 @@ And many include an optional upsert clause. You can unconditionally upsert using
363363
@Column {
364364
```swift
365365
Reminder.insert {
366-
($0.isCompleted, $0.title, $0.priority)
366+
($0.isCompleted, $0.priority, $0.title)
367367
} values: {
368-
(false, "Get groceries", 3)
368+
(false, .high, "Get groceries")
369369
} onConflictDoUpdate: {
370370
$0.title += " (Copy)"
371371
}
@@ -376,9 +376,7 @@ And many include an optional upsert clause. You can unconditionally upsert using
376376
INSERT INTO "reminders"
377377
("isCompleted", "title", "priority")
378378
VALUES
379-
(0, 'Get groceries', 3),
380-
(0, 'Take a walk', 1),
381-
(1, 'Get haircut', NULL)
379+
(0, 3, 'Get groceries'),
382380
ON CONFLICT DO UPDATE SET
383381
"title" = ("reminders"."title" || ' (Copy)')
384382
```
@@ -391,11 +389,11 @@ Or you can conditionally upsert from given indexed columns using `onConflict:doU
391389
@Column {
392390
```swift
393391
Reminder.insert {
394-
($0.isCompleted, $0.title, $0.priority)
392+
($0.isCompleted, $0.priority, $0.title)
395393
} values: {
396-
(false, "Get groceries", 3)
394+
(false, .high, "Get groceries")
397395
} onConflict: {
398-
$0.id
396+
$0.title
399397
} doUpdate: {
400398
$0.title += " (Copy)"
401399
}
@@ -404,17 +402,48 @@ Or you can conditionally upsert from given indexed columns using `onConflict:doU
404402
@Column {
405403
```sql
406404
INSERT INTO "reminders"
407-
("isCompleted", "title", "priority")
405+
("isCompleted", "priority", "title")
408406
VALUES
409-
(0, 'Get groceries', 3),
410-
(0, 'Take a walk', 1),
411-
(1, 'Get haircut', NULL)
412-
ON CONFLICT ("id") DO UPDATE SET
407+
(0, 3, 'Get groceries'),
408+
ON CONFLICT ("title") DO UPDATE SET
413409
"title" = ("reminders"."title" || ' (Copy)')
414410
```
415411
}
416412
}
417413

414+
Upsert clauses have an additional, special ``Updates/excluded`` qualifier for referring to a row
415+
that failed to insert.
416+
417+
```swift
418+
@Row {
419+
@Column {
420+
```swift
421+
Reminder.insert {
422+
($0.isCompleted, $0.priority, $0.title)
423+
} values: {
424+
(false, .high, "Get groceries")
425+
} onConflict: {
426+
$0.title
427+
} doUpdate: {
428+
$0.isCompleted = $0.excluded.isCompleted
429+
$0.priority = $0.excluded.priority
430+
}
431+
```
432+
}
433+
@Column {
434+
```sql
435+
INSERT INTO "reminders"
436+
("isCompleted", "priority", "title")
437+
VALUES
438+
(0, 3, 'Get groceries'),
439+
ON CONFLICT ("title") DO UPDATE SET
440+
"isCompleted" = "excluded"."isCompleted",
441+
"priority" = "excluded"."priority"
442+
```
443+
}
444+
}
445+
```
446+
418447
`WHERE` conditions are also supported, on both the conflict and update clauses.
419448

420449
> Tip: The `onConflictDoUpdate` and `doUpdate` closures work similarly to the closure parameter of
@@ -438,6 +467,10 @@ Or you can conditionally upsert from given indexed columns using `onConflict:doU
438467

439468
- ``Table/insert(or:_:select:onConflict:where:doUpdate:where:)``
440469

470+
### Upserts
471+
472+
- ``Table/Excluded``
473+
441474
### Statement types
442475

443476
- ``Insert``

0 commit comments

Comments
 (0)