Skip to content

Commit

Permalink
Fix behavior of SQLColumn when "*" is specified as a column name (#181)
Browse files Browse the repository at this point in the history
Fix behavior of SQLColumn when "*" is specified as a column name (this behavior belonged in SQLColumn, not in SQLUnqualifiedColumnListBuilder) and add tests. Fixes #180.
  • Loading branch information
gwynne committed Jun 11, 2024
1 parent 14f4350 commit f697d32
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ extension SQLUnqualifiedColumnListBuilder {
@inlinable
@discardableResult
public func column(_ column: String) -> Self {
self.column(column == "*" ? SQLLiteral.all : SQLColumn(column))
self.column(SQLColumn(column))
}

/// Specify a single column to be included in the list of columns for the query.
Expand All @@ -36,7 +36,7 @@ extension SQLUnqualifiedColumnListBuilder {
@inlinable
@discardableResult
public func columns(_ columns: [String]) -> Self {
self.columns(columns.map { $0 == "*" ? SQLLiteral.all as any SQLExpression : SQLColumn($0) })
self.columns(columns.map { SQLColumn($0) })
}

/// Specify mutiple columns to be included in the list of columns for the query.
Expand Down
16 changes: 12 additions & 4 deletions Sources/SQLKit/Expressions/Basics/SQLColumn.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
/// An expression representing an optionally table-qualified column in an SQL table.
public struct SQLColumn: SQLExpression {
/// The column name, usually an ``SQLIdentifier``.
/// The column name.
///
/// Usually an ``SQLIdentifier``.
public var name: any SQLExpression

/// If specified, the table to which the column belongs. Usually an ``SQLIdentifier`` when not `nil`.
/// If specified, the table to which the column belongs.
///
/// Usually an ``SQLIdentifier`` or ``SQLQualifiedTable`` when not `nil`.
public var table: (any SQLExpression)?

/// Create an ``SQLColumn`` from a name and optional table name.
///
/// A column name of `*` is treated as ``SQLLiteral/all`` rather than as an identifier. To specify a column whose
/// actual name consists of a sole asterisk (probably not a good idea to have one of those in the first place),
/// use ``init(_:table:)-77d24`` and `SQLIdentifier("*")`.
@inlinable
public init(_ name: String, table: String? = nil) {
self.init(SQLIdentifier(name), table: table.flatMap(SQLIdentifier.init(_:)))
self.init(name == "*" ? SQLLiteral.all : SQLIdentifier(name), table: table.flatMap(SQLIdentifier.init(_:)))
}

/// Create an ``SQLColumn`` from an identifier and optional table identifier.
/// Create an ``SQLColumn`` from an identifier and optional table expression.
@inlinable
public init(_ name: any SQLExpression, table: (any SQLExpression)? = nil) {
self.name = name
Expand Down
10 changes: 8 additions & 2 deletions Tests/SQLKitTests/BasicQueryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,22 @@ final class BasicQueryTests: XCTestCase {

// MARK: Select

func testSelect_unqualifiedColums() {
func testSelect_unqualifiedColumns() {
XCTAssertSerialization(
of: self.db.select()
.column("*")
.column("name")
.column(SQLLiteral.all)
.column(SQLIdentifier("name"))
.columns("*")
.columns("name")
.columns(["*"])
.columns(["name"])
.columns(SQLLiteral.all)
.columns(SQLIdentifier("name"))
.columns([SQLLiteral.all])
.columns([SQLIdentifier("name")]),
is: "SELECT ``name``, ``name``, ``name``, ``name``, ``name``, ``name``"
is: "SELECT *, ``name``, *, ``name``, *, ``name``, *, ``name``, *, ``name``, *, ``name``"
)
}

Expand Down
9 changes: 9 additions & 0 deletions Tests/SQLKitTests/SQLExpressionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,13 @@ final class SQLExpressionTests: XCTestCase {
self.db._dialect.literalStringQuote = SQLQueryString("~")
XCTAssertSerialization(of: self.db.raw("\(ident: "hello") \(literal: "there")"), is: "_hello_ ~there~")
}

func testColumns() {
XCTAssertSerialization(of: self.db.raw("\(SQLColumn("*"))"), is: "*")
XCTAssertSerialization(of: self.db.raw("\(SQLColumn(SQLIdentifier("*")))"), is: "``*``")
XCTAssertSerialization(of: self.db.raw("\(SQLColumn(SQLLiteral.all))"), is: "*")
XCTAssertSerialization(of: self.db.raw("\(SQLColumn("*", table: "foo"))"), is: "``foo``.*")
XCTAssertSerialization(of: self.db.raw("\(SQLColumn(SQLIdentifier("*"), table: SQLIdentifier("foo")))"), is: "``foo``.``*``")
XCTAssertSerialization(of: self.db.raw("\(SQLColumn(SQLLiteral.all, table: SQLIdentifier("foo")))"), is: "``foo``.*")
}
}

0 comments on commit f697d32

Please sign in to comment.