Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ reminder is inserted into the database with the following trigger:

- ``StructuredQueriesCore/Table/createTemporaryTrigger(_:ifNotExists:after:fileID:line:column:)``
- ``StructuredQueriesCore/Table/createTemporaryTrigger(_:ifNotExists:before:fileID:line:column:)``
- ``StructuredQueriesCore/Table/createTemporaryTrigger(_:ifNotExists:insteadOf:fileID:line:column:)``

### Touching records

Expand Down
37 changes: 37 additions & 0 deletions Sources/StructuredQueriesSQLiteCore/Triggers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,42 @@ extension Table {
)
}

/// A `CREATE TEMPORARY TRIGGER` statement that executes instead of a database view event.
///
/// See <doc:Triggers> for more information.
///
/// > Important: A name for the trigger is automatically derived from the arguments if one is not
/// > provided. If you build your own trigger helper that call this function, then your helper
/// > should also take `fileID`, `line` and `column` arguments and pass them to this function.
///
/// - Parameters:
/// - name: The trigger's name. By default a unique name is generated depending using the table,
/// operation, and source location.
/// - ifNotExists: Adds an `IF NOT EXISTS` clause to the `CREATE TRIGGER` statement.
/// - operation: The trigger's operation.
/// - fileID: The source `#fileID` associated with the trigger.
/// - line: The source `#line` associated with the trigger.
/// - column: The source `#column` associated with the trigger.
/// - Returns: A temporary trigger.
public static func createTemporaryTrigger(
_ name: String? = nil,
ifNotExists: Bool = false,
insteadOf operation: TemporaryTrigger<Self>.Operation,
fileID: StaticString = #fileID,
line: UInt = #line,
column: UInt = #column
) -> TemporaryTrigger<Self> {
TemporaryTrigger(
name: name,
ifNotExists: ifNotExists,
operation: operation,
when: .insteadOf,
fileID: fileID,
line: line,
column: column
)
}

/// A `CREATE TEMPORARY TRIGGER` statement that applies additional updates to a row that has just
/// been updated.
///
Expand Down Expand Up @@ -252,6 +288,7 @@ public struct TemporaryTrigger<On: Table>: Sendable, Statement {
fileprivate enum When: QueryFragment {
case before = "BEFORE"
case after = "AFTER"
case insteadOf = "INSTEAD OF"
}

/// The database event used in a trigger.
Expand Down
53 changes: 53 additions & 0 deletions Tests/StructuredQueriesTests/ViewsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,59 @@ extension SnapshotTests {
└────────────────────────┘
"""
}
assertQuery(
CompletedReminder.createTemporaryTrigger(
insteadOf: .insert { new in
Reminder.insert {
($0.title, $0.isCompleted, $0.remindersListID)
} values: {
(new.title, true, 1)
}
}
)
) {
"""
CREATE TEMPORARY TRIGGER
"after_insert_on_completedReminders@StructuredQueriesTests/ViewsTests.swift:58:49"
INSTEAD OF INSERT ON "completedReminders"
FOR EACH ROW BEGIN
INSERT INTO "reminders"
("title", "isCompleted", "remindersListID")
VALUES
("new"."title", 1, 1);
END
"""
}
assertQuery(
CompletedReminder.insert(\.title) { "Already done" }
) {
"""
INSERT INTO "completedReminders"
("title")
VALUES
('Already done')
"""
}
// NB: Can't use 'RETURNING' above due to a SQLite bug where 'reminderID' is 'NULL'.
assertQuery(
CompletedReminder.order { $0.reminderID.desc() }.limit(1)
) {
"""
SELECT "completedReminders"."reminderID", "completedReminders"."title"
FROM "completedReminders"
ORDER BY "completedReminders"."reminderID" DESC
LIMIT 1
"""
} results: {
"""
┌─────────────────────────┐
│ CompletedReminder( │
│ reminderID: 11, │
│ title: "Already done" │
│ ) │
└─────────────────────────┘
"""
}
assertQuery(
query.drop()
) {
Expand Down