Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 5 additions & 0 deletions Sources/StructuredQueriesCore/Internal/Scope.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
enum Scope {
case unscoped
case `default`
case empty
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,28 @@ public struct With<QueryValue>: Statement {
}

public var query: QueryFragment {
guard !statement.isEmpty else { return "" }
let cteFragments = ctes.compactMap(\.queryFragment.presence)
guard !cteFragments.isEmpty else { return "" }
var query: QueryFragment = "WITH "
query.append(
"\(ctes.map(\.queryFragment).joined(separator: ", "))\(.newlineOrSpace)\(statement)"
"\(cteFragments.joined(separator: ", "))\(.newlineOrSpace)\(statement)"
)
return query
}
}

extension QueryFragment {
fileprivate var presence: Self? { isEmpty ? nil : self }
}

public struct CommonTableExpressionClause: QueryExpression {
public typealias QueryValue = ()
let tableName: QueryFragment
let select: QueryFragment
public var queryFragment: QueryFragment {
"\(tableName) AS (\(.newline)\(select.indented())\(.newline))"
guard !select.isEmpty else { return "" }
return "\(tableName) AS (\(.newline)\(select.indented())\(.newline))"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ private struct CompoundSelect<QueryValue>: PartialSelectStatement {
}

var query: QueryFragment {
"\(lhs)\(.newlineOrSpace)\(`operator`.indented())\(.newlineOrSpace)\(rhs)"
guard !lhs.isEmpty else { return rhs }
guard !rhs.isEmpty else { return lhs }
return "\(lhs)\(.newlineOrSpace)\(`operator`.indented())\(.newlineOrSpace)\(rhs)"
}
}
18 changes: 16 additions & 2 deletions Sources/StructuredQueriesCore/Statements/Delete.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extension Table {
///
/// - Returns: A delete statement.
public static func delete() -> DeleteOf<Self> {
Delete()
Delete(isEmpty: false)
}
}

Expand All @@ -23,7 +23,7 @@ extension PrimaryKeyedTable {
/// - Parameter row: A row to delete.
/// - Returns: A delete statement.
public static func delete(_ row: Self) -> DeleteOf<Self> {
Delete()
delete()
.where {
$0.primaryKey.eq(TableColumns.PrimaryKey(queryOutput: row[keyPath: $0.primaryKey.keyPath]))
}
Expand All @@ -36,6 +36,7 @@ extension PrimaryKeyedTable {
///
/// To learn more, see <doc:DeleteStatements>.
public struct Delete<From: Table, Returning> {
var isEmpty: Bool
var `where`: [QueryFragment] = []
var returning: [QueryFragment] = []

Expand Down Expand Up @@ -107,6 +108,7 @@ public struct Delete<From: Table, Returning> {
returning.append("\(quote: resultColumn.name)")
}
return Delete<From, (repeat each QueryValue)>(
isEmpty: isEmpty,
where: `where`,
returning: Array(repeat each selection(From.columns))
)
Expand All @@ -126,10 +128,21 @@ public struct Delete<From: Table, Returning> {
returning.append("\(quote: resultColumn.name)")
}
return Delete<From, From>(
isEmpty: isEmpty,
where: `where`,
returning: returning
)
}

public var unscoped: Delete<From, ()> {
From.unscoped.delete()
}

public var none: Self {
var delete = self
delete.isEmpty = true
return delete
}
}

/// A convenience type alias for a non-`RETURNING ``Delete``.
Expand All @@ -139,6 +152,7 @@ extension Delete: Statement {
public typealias QueryValue = Returning

public var query: QueryFragment {
guard !isEmpty else { return "" }
var query: QueryFragment = "DELETE FROM "
if let schemaName = From.schemaName {
query.append("\(quote: schemaName).")
Expand Down
41 changes: 40 additions & 1 deletion Sources/StructuredQueriesCore/Statements/Select.swift
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ extension Table {
}

public struct _SelectClauses: Sendable {
var isEmpty = false
var distinct = false
var columns: [any QueryExpression] = []
var joins: [_JoinClause] = []
Expand All @@ -320,6 +321,11 @@ public struct Select<Columns, From: Table, Joins> {
// NB: A parameter pack compiler crash forces us to heap-allocate this storage.
@CopyOnWrite var clauses = _SelectClauses()

fileprivate var isEmpty: Bool {
get { clauses.isEmpty }
set { clauses.isEmpty = newValue }
_modify { yield &clauses.isEmpty }
}
fileprivate var distinct: Bool {
get { clauses.distinct }
set { clauses.distinct = newValue }
Expand Down Expand Up @@ -362,6 +368,7 @@ public struct Select<Columns, From: Table, Joins> {
}

fileprivate init(
isEmpty: Bool,
distinct: Bool,
columns: [any QueryExpression],
joins: [_JoinClause],
Expand All @@ -371,6 +378,7 @@ public struct Select<Columns, From: Table, Joins> {
order: [QueryFragment],
limit: _LimitClause?
) {
self.isEmpty = isEmpty
self.columns = columns
self.distinct = distinct
self.joins = joins
Expand All @@ -387,7 +395,8 @@ public struct Select<Columns, From: Table, Joins> {
}

extension Select {
init(where: [QueryFragment] = []) {
init(isEmpty: Bool = false, where: [QueryFragment] = []) {
self.isEmpty = isEmpty
self.where = `where`
}

Expand Down Expand Up @@ -558,6 +567,7 @@ extension Select {
Joins == (repeat each J)
{
Select<(repeat each C1, repeat (each C2).QueryValue), From, (repeat each J)>(
isEmpty: isEmpty,
distinct: distinct,
columns: columns + Array(repeat each selection((From.columns, repeat (each J).columns))),
joins: joins,
Expand Down Expand Up @@ -612,6 +622,7 @@ extension Select {
)
)
return Select<(repeat each C1, repeat each C2), From, (repeat each J1, F, repeat each J2)>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -651,6 +662,7 @@ extension Select {
)
)
return Select<(repeat each C1, repeat each C2), From, (repeat each J, F)>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -686,6 +698,7 @@ extension Select {
)
)
return Select<QueryValue, From, (F, repeat each J)>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -738,6 +751,7 @@ extension Select {
From,
(repeat each J1, F._Optionalized, repeat (each J2)._Optionalized)
>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -785,6 +799,7 @@ extension Select {
From,
(repeat each J, F._Optionalized)
>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -822,6 +837,7 @@ extension Select {
)
)
return Select<QueryValue, From, (F._Optionalized, repeat (each J)._Optionalized)>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -874,6 +890,7 @@ extension Select {
From._Optionalized,
(repeat (each J1)._Optionalized, F, repeat each J2)
>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -921,6 +938,7 @@ extension Select {
From._Optionalized,
(repeat (each J)._Optionalized, F)
>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -958,6 +976,7 @@ extension Select {
)
)
return Select<QueryValue, From._Optionalized, (F, repeat each J)>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -1010,6 +1029,7 @@ extension Select {
From._Optionalized,
(repeat (each J1)._Optionalized, F._Optionalized, repeat (each J2)._Optionalized)
>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -1057,6 +1077,7 @@ extension Select {
From._Optionalized,
(repeat (each J)._Optionalized, F._Optionalized)
>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -1094,6 +1115,7 @@ extension Select {
)
)
return Select<QueryValue, From._Optionalized, (F._Optionalized, repeat (each J)._Optionalized)>(
isEmpty: isEmpty || other.isEmpty,
distinct: distinct || other.distinct,
columns: columns + other.columns,
joins: joins + [join] + other.joins,
Expand Down Expand Up @@ -1348,6 +1370,7 @@ extension Select {
SQLQueryExpression(iterator.next()!.queryFragment)
}
return Select<(repeat (each C2).QueryValue), From, Joins>(
isEmpty: isEmpty,
distinct: distinct,
columns: Array(repeat each transform(repeat { _ in next() }((each C1).self))),
joins: joins,
Expand All @@ -1358,6 +1381,20 @@ extension Select {
limit: limit
)
}

public var unscoped: Where<From> {
From.unscoped
}

public var all: Self {
self
}

public var none: Self {
var select = self
select.isEmpty = true
return select
}
}

/// Combines two select statements of the same table type together.
Expand Down Expand Up @@ -1387,6 +1424,7 @@ public func + <
return Select<
(repeat each C1, repeat each C2), From, (repeat each J1, repeat each J2)
>(
isEmpty: lhs.isEmpty || rhs.isEmpty,
distinct: lhs.distinct || rhs.distinct,
columns: lhs.columns + rhs.columns,
joins: lhs.joins + rhs.joins,
Expand All @@ -1406,6 +1444,7 @@ extension Select: SelectStatement {
}

public var query: QueryFragment {
guard !isEmpty else { return "" }
var query: QueryFragment = "SELECT"
let columns =
columns.isEmpty
Expand Down
17 changes: 15 additions & 2 deletions Sources/StructuredQueriesCore/Statements/Update.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ extension Table {
or conflictResolution: ConflictResolution? = nil,
set updates: (inout Updates<Self>) -> Void
) -> UpdateOf<Self> {
Update(conflictResolution: conflictResolution, updates: Updates(updates))
Update(isEmpty: false, conflictResolution: conflictResolution, updates: Updates(updates))
}
}

Expand Down Expand Up @@ -91,6 +91,7 @@ extension PrimaryKeyedTable {
///
/// To learn more, see <doc:UpdateStatements>.
public struct Update<From: Table, Returning> {
var isEmpty: Bool
var conflictResolution: ConflictResolution?
var updates: Updates<From>
var `where`: [QueryFragment] = []
Expand Down Expand Up @@ -159,6 +160,7 @@ public struct Update<From: Table, Returning> {
returning.append("\(quote: resultColumn.name)")
}
return Update<From, (repeat each QueryValue)>(
isEmpty: false,
conflictResolution: conflictResolution,
updates: updates,
where: `where`,
Expand All @@ -180,12 +182,23 @@ public struct Update<From: Table, Returning> {
returning.append("\(quote: resultColumn.name)")
}
return Update<From, From>(
isEmpty: isEmpty,
conflictResolution: conflictResolution,
updates: updates,
where: `where`,
returning: returning
)
}

public var unscoped: Delete<From, ()> {
From.unscoped.delete()
}

public var none: Self {
var delete = self
delete.isEmpty = true
return delete
}
}

/// A convenience type alias for a non-`RETURNING ``Update``.
Expand All @@ -195,7 +208,7 @@ extension Update: Statement {
public typealias QueryValue = Returning

public var query: QueryFragment {
guard !updates.isEmpty
guard !isEmpty, !updates.isEmpty
else { return "" }

var query: QueryFragment = "UPDATE "
Expand Down
Loading