Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
70 changes: 70 additions & 0 deletions Sources/StructuredQueriesSQLiteCore/Views.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
extension Table where Self: _Selection {
/// A `CREATE TEMPORARY VIEW` statement that executes after a database 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 createTemporaryView<Selection: SelectStatement>(
ifNotExists: Bool = false,
select: () -> Selection
) -> DatabaseView<Self, Selection>
where Selection.QueryValue == Columns.QueryValue {
DatabaseView(ifNotExists: ifNotExists, select: select())
}
}

public struct DatabaseView<View: Table & _Selection, Selection: SelectStatement>: Statement
where Selection.QueryValue == View {
public typealias QueryValue = ()
public typealias From = Never

fileprivate let ifNotExists: Bool
fileprivate let select: Selection

/// Returns a `DROP VIEW` statement for this trigger.
///
/// - Parameter ifExists: Adds an `IF EXISTS` condition to the `DROP VIEW`.
/// - Returns: A `DROP VIEW` statement for this trigger.
public func drop(ifExists: Bool = false) -> some Statement<()> {
var query: QueryFragment = "DROP VIEW"
if ifExists {
query.append(" IF EXISTS")
}
query.append(" ")
if let schemaName = View.schemaName {
query.append("\(quote: schemaName).")
}
query.append(View.tableFragment)
return SQLQueryExpression(query)
}

public var query: QueryFragment {
var query: QueryFragment = "CREATE TEMPORARY VIEW"
if ifNotExists {
query.append(" IF NOT EXISTS")
}
query.append(.newlineOrSpace)
if let schemaName = View.schemaName {
query.append("\(quote: schemaName).")
}
query.append(View.tableFragment)
let columnNames: [QueryFragment] = View.TableColumns.allColumns
.map { "\(quote: $0.name)" }
query.append("\(.newlineOrSpace)(\(columnNames.joined(separator: ", ")))")
query.append("\(.newlineOrSpace)AS")
query.append("\(.newlineOrSpace)\(select)")
return query
}
}
76 changes: 76 additions & 0 deletions Tests/StructuredQueriesTests/ViewsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import Dependencies
import Foundation
import InlineSnapshotTesting
import StructuredQueries
import Testing
import _StructuredQueriesSQLite

extension SnapshotTests {
@Suite struct ViewsTests {
@Test func basics() {
let query = CompletedReminder.createTemporaryView {
Reminder
.where(\.isCompleted)
.select { CompletedReminder.Columns(reminderID: $0.id, title: $0.title) }
}
assertQuery(
query
) {
"""
CREATE TEMPORARY VIEW
"completedReminders"
("reminderID", "title")
AS
SELECT "reminders"."id" AS "reminderID", "reminders"."title" AS "title"
FROM "reminders"
WHERE "reminders"."isCompleted"
"""
} results: {
"""

"""
}
assertQuery(
CompletedReminder.limit(2)
) {
"""
SELECT "completedReminders"."reminderID", "completedReminders"."title"
FROM "completedReminders"
LIMIT 2
"""
} results: {
"""
┌────────────────────────┐
│ CompletedReminder( │
│ reminderID: 4, │
│ title: "Take a walk" │
│ ) │
├────────────────────────┤
│ CompletedReminder( │
│ reminderID: 7, │
│ title: "Get laundry" │
│ ) │
└────────────────────────┘
"""
}
assertQuery(
query.drop()
) {
"""
DROP VIEW
"completedReminders"
"""
}
}
}
}

@Table @Selection
private struct CompletedReminder {
let reminderID: Reminder.ID
let title: String
}

extension Table where Self: _Selection {
static func foo() {}
}
Loading