// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. // // stringlint:disable import Foundation import GRDB public extension SQLInterpolation { /// Appends the table name of the record type. /// /// // SELECT * FROM player /// let player: TypedTableAlias = TypedTableAlias() /// let request: SQLRequest = "SELECT * FROM \(player)" @_disfavoredOverload mutating func appendInterpolation(_ typedTableAlias: TypedTableAlias) { let name: String = typedTableAlias.name guard let tableName: String = typedTableAlias.tableName else { return appendLiteral(name.quotedDatabaseIdentifier) } guard name != tableName else { return appendLiteral(tableName.quotedDatabaseIdentifier) } appendLiteral("\(tableName.quotedDatabaseIdentifier) AS \(name.quotedDatabaseIdentifier)") } /// Appends a simple SQL query for use when we want a `LEFT JOIN` that will always fail /// /// // SELECT * FROM player LEFT JOIN team AS testTeam ON false /// let player: TypedTableAlias = TypedTableAlias() /// let testTeam: TypedTableAlias = TypedTableAlias(name: "testTeam") /// let request: SQLRequest = "SELECT * FROM \(player) LEFT JOIN \(testTeam.never) @_disfavoredOverload mutating func appendInterpolation(_ neverJoiningAlias: NeverJoiningTypedTableAlias) where T: TableRecord { guard let tableName: String = neverJoiningAlias.alias.tableName else { appendLiteral("(SELECT \(generateSelection(for: T.self))) AS \(neverJoiningAlias.alias.name.quotedDatabaseIdentifier) ON false") return } appendLiteral("\(tableName.quotedDatabaseIdentifier) AS \(neverJoiningAlias.alias.name.quotedDatabaseIdentifier) ON false") } /// Appends a simple SQL query for use when we want a `LEFT JOIN` that will always fail /// /// // SELECT * FROM player LEFT JOIN (SELECT 0 AS teamInfo.Column.A, 0 AS teamInfo.Column.B) AS teamInfo ON false /// let player: TypedTableAlias = TypedTableAlias() /// let teamInfo: TypedTableAlias = TypedTableAlias(name: "teamInfo") /// let request: SQLRequest = "SELECT * FROM \(player) LEFT JOIN \(teamInfo.never) @_disfavoredOverload mutating func appendInterpolation(_ neverJoiningAlias: NeverJoiningTypedTableAlias) where T.Columns: CaseIterable { appendLiteral("(SELECT \(generateSelection(for: T.self))) AS \(neverJoiningAlias.alias.name.quotedDatabaseIdentifier) ON false") } /// Appends a simple SQL query for use when we want a `LEFT JOIN` that will always fail /// /// // SELECT * FROM player LEFT JOIN (SELECT 0 AS teamInfo.Column.A, 0 AS teamInfo.Column.B) AS teamInfo ON false /// let player: TypedTableAlias = TypedTableAlias() /// let teamInfo: TypedTableAlias = TypedTableAlias(name: "teamInfo") /// let request: SQLRequest = "SELECT * FROM \(player) LEFT JOIN \(teamInfo.never) @_disfavoredOverload mutating func appendInterpolation(_ neverJoiningAlias: NeverJoiningTypedTableAlias) { appendLiteral("(SELECT \(generateSelection(for: T.self))) AS \(neverJoiningAlias.alias.name.quotedDatabaseIdentifier) ON false") } private func generateSelection(for type: T.Type) -> String where T.Columns: CaseIterable { return T.Columns.allCases .map { "NULL AS \($0.name)" } .joined(separator: ", ") } private func generateSelection(for type: T.Type) -> String { return "SELECT 1" } }