SQLite.swift
SQLite.swift copied to clipboard
Aliased NOT EXISTS and an aliased column as part of SELECT
Is there a way to express the following query with the help of the library?
SELECT
expo.id AS expo_id,
(SELECT COUNT(*) FROM lead) lead_count,
NOT EXISTS(SELECT * FROM lead WHERE result <> 1) leads_synced
FROM expo
If so, then could you give an example? After looking at the tests and skimming through the sources, I don't believe it's currently possible though. Maybe something for the future releases then.
So for now I work around the issue using the following code. Maybe something to include into the library by default. If the repo owner confirms in the comments below that he approves of such an addition, I could prepare a pull request:
import Foundation
import SQLite
/// In case it's necessary to execute a SQL query that is currently not possible
/// to express in a type-safe manner using SQLite.swift library, prepare a raw
/// SQL statement and map the resulting rows to TypedRow, which will then cast
/// the column values to the user specified types.
///
/// Example code:
///
/// let statement = try db.prepare("SELECT expo.id AS expo_id FROM expo")
/// let rows = statement.typedRows()
/// let expos = rows.map { let id = $0.i64("expo_id"); return ... }
public final class TypedRow {
private var columns: [String: Int]
private var values: [Binding?]
public init(columns theColumns: [String: Int], values theValues: [Binding?]) {
columns = theColumns
values = theValues
}
public convenience init(columns: [String], values: [Binding?]) {
self.init(columns: columns.invertedIndexedDictionary, values: values)
}
private func value(for column: String) -> Binding? {
return values[columns[column]!]
}
public func i64(_ column: String) -> Int64? {
return value(for: column) as? Int64
}
public func int(_ column: String) -> Int? {
return value(for: column) as? Int
}
public func u32(_ column: String) -> UInt32? {
return value(for: column) as? UInt32
}
public func bool(_ column: String) -> Bool {
return (value(for: column) as? Bool) ?? false
}
public func string(_ column: String) -> String? {
return value(for: column) as? String
}
public func date(_ column: String) -> Date? {
guard let rawValue = value(for: column) as? Int64 else { return nil }
return rawValue.dateFromSQLiteTime()
}
}
fileprivate extension Array where Element: Hashable {
var invertedIndexedDictionary: [Element: Int] {
var result: [Element: Int] = [:]
enumerated().forEach { result[$0.element] = $0.offset }
return result
}
}
public extension Statement {
public func typedRows() -> [TypedRow] {
return map { TypedRow(columns: columnNames, values: $0) }
}
}