#if !USING_BUILTIN_SQLITE #if os(OSX) import SQLiteMacOSX #elseif os(iOS) #if (arch(i386) || arch(x86_64)) import SQLiteiPhoneSimulator #else import SQLiteiPhoneOS #endif #endif #endif // MARK: - _SQLSelectQuery /// This type is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public struct _SQLSelectQuery { var selection: [_SQLSelectable] var distinct: Bool var source: _SQLSource? var whereExpression: _SQLExpression? var groupByExpressions: [_SQLExpression] var orderings: [_SQLOrdering] var reversed: Bool var havingExpression: _SQLExpression? var limit: _SQLLimit? init( select selection: [_SQLSelectable], distinct: Bool = false, from source: _SQLSource? = nil, filter whereExpression: _SQLExpression? = nil, groupBy groupByExpressions: [_SQLExpression] = [], orderBy orderings: [_SQLOrdering] = [], reversed: Bool = false, having havingExpression: _SQLExpression? = nil, limit: _SQLLimit? = nil) { self.selection = selection self.distinct = distinct self.source = source self.whereExpression = whereExpression self.groupByExpressions = groupByExpressions self.orderings = orderings self.reversed = reversed self.havingExpression = havingExpression self.limit = limit } func sql(inout arguments: StatementArguments?) -> String { var sql = "SELECT" if distinct { sql += " DISTINCT" } assert(!selection.isEmpty) sql += " " + selection.map { $0.resultColumnSQL(&arguments) }.joinWithSeparator(", ") if let source = source { sql += " FROM " + source.sql(&arguments) } if let whereExpression = whereExpression { sql += " WHERE " + whereExpression.sql(&arguments) } if !groupByExpressions.isEmpty { sql += " GROUP BY " + groupByExpressions.map { $0.sql(&arguments) }.joinWithSeparator(", ") } if let havingExpression = havingExpression { sql += " HAVING " + havingExpression.sql(&arguments) } var orderings = self.orderings if reversed { if orderings.isEmpty { // https://www.sqlite.org/lang_createtable.html#rowid // // > The rowid value can be accessed using one of the special // > case-independent names "rowid", "oid", or "_rowid_" in // > place of a column name. If a table contains a user defined // > column named "rowid", "oid" or "_rowid_", then that name // > always refers the explicitly declared column and cannot be // > used to retrieve the integer rowid value. // // Here we assume that _rowid_ is not a custom column. // TODO: support for user-defined _rowid_ column. // TODO: support for WITHOUT ROWID tables. orderings = [SQLColumn("_rowid_").desc] } else { orderings = orderings.map { $0.reversedSortDescriptor } } } if !orderings.isEmpty { sql += " ORDER BY " + orderings.map { $0.orderingSQL(&arguments) }.joinWithSeparator(", ") } if let limit = limit { sql += " LIMIT " + limit.sql } return sql } /// Returns a query that counts the number of rows matched by self. var countQuery: _SQLSelectQuery { guard groupByExpressions.isEmpty && limit == nil else { // SELECT ... GROUP BY ... // SELECT ... LIMIT ... return trivialCountQuery } guard let source = source, case .Table(name: let tableName, alias: let alias) = source else { // SELECT ... FROM (something which is not a table) return trivialCountQuery } assert(!selection.isEmpty) if selection.count == 1 { let selectable = self.selection[0] switch selectable.sqlSelectableKind { case .Star(sourceName: let sourceName): guard !distinct else { return trivialCountQuery } if let sourceName = sourceName { guard sourceName == tableName || sourceName == alias else { return trivialCountQuery } } // SELECT * FROM tableName ... // -> // SELECT COUNT(*) FROM tableName ... var countQuery = unorderedQuery countQuery.selection = [_SQLExpression.Count(selectable)] return countQuery case .Expression(let expression): // SELECT [DISTINCT] expr FROM tableName ... if distinct { // SELECT DISTINCT expr FROM tableName ... // -> // SELECT COUNT(DISTINCT expr) FROM tableName ... var countQuery = unorderedQuery countQuery.distinct = false countQuery.selection = [_SQLExpression.CountDistinct(expression)] return countQuery } else { // SELECT expr FROM tableName ... // -> // SELECT COUNT(*) FROM tableName ... var countQuery = unorderedQuery countQuery.selection = [_SQLExpression.Count(_SQLResultColumn.Star(nil))] return countQuery } } } else { // SELECT [DISTINCT] expr1, expr2, ... FROM tableName ... guard !distinct else { return trivialCountQuery } // SELECT expr1, expr2, ... FROM tableName ... // -> // SELECT COUNT(*) FROM tableName ... var countQuery = unorderedQuery countQuery.selection = [_SQLExpression.Count(_SQLResultColumn.Star(nil))] return countQuery } } // SELECT COUNT(*) FROM (self) private var trivialCountQuery: _SQLSelectQuery { return _SQLSelectQuery( select: [_SQLExpression.Count(_SQLResultColumn.Star(nil))], from: .Query(query: unorderedQuery, alias: nil)) } /// Remove ordering private var unorderedQuery: _SQLSelectQuery { var query = self query.reversed = false query.orderings = [] return query } } // MARK: - _SQLSource indirect enum _SQLSource { case Table(name: String, alias: String?) case Query(query: _SQLSelectQuery, alias: String?) func sql(inout arguments: StatementArguments?) -> String { switch self { case .Table(let table, let alias): if let alias = alias { return table.quotedDatabaseIdentifier + " AS " + alias.quotedDatabaseIdentifier } else { return table.quotedDatabaseIdentifier } case .Query(let query, let alias): if let alias = alias { return "(" + query.sql(&arguments) + ") AS " + alias.quotedDatabaseIdentifier } else { return "(" + query.sql(&arguments) + ")" } } } } // MARK: - _SQLOrdering /// This protocol is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public protocol _SQLOrdering { var reversedSortDescriptor: _SQLSortDescriptor { get } func orderingSQL(inout arguments: StatementArguments?) -> String } /// This type is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public enum _SQLSortDescriptor { case Asc(_SQLExpression) case Desc(_SQLExpression) } extension _SQLSortDescriptor : _SQLOrdering { /// This property is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public var reversedSortDescriptor: _SQLSortDescriptor { switch self { case .Asc(let expression): return .Desc(expression) case .Desc(let expression): return .Asc(expression) } } /// This method is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public func orderingSQL(inout arguments: StatementArguments?) -> String { switch self { case .Asc(let expression): return expression.sql(&arguments) + " ASC" case .Desc(let expression): return expression.sql(&arguments) + " DESC" } } } // MARK: - _SQLLimit struct _SQLLimit { let limit: Int let offset: Int? var sql: String { if let offset = offset { return "\(limit) OFFSET \(offset)" } else { return "\(limit)" } } } // MARK: - _SQLExpressible public protocol _SQLExpressible { /// This property is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface var sqlExpression: _SQLExpression { get } } // Conformance to _SQLExpressible extension DatabaseValueConvertible { /// This property is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public var sqlExpression: _SQLExpression { return .Value(self) } } /// This protocol is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public protocol _SpecificSQLExpressible : _SQLExpressible { // _SQLExpressible can be adopted by Swift standard types, and user // types, through the DatabaseValueConvertible protocol, which inherits // from _SQLExpressible. // // For example, Int adopts _SQLExpressible through // DatabaseValueConvertible. // // _SpecificSQLExpressible, on the other side, is not adopted by any // Swift standard type or any user type. It is only adopted by GRDB types, // such as SQLColumn and _SQLExpression. // // This separation lets us define functions and operators that do not // spill out. The three declarations below have no chance overloading a // Swift-defined operator, or a user-defined operator: // // - ==(_SQLExpressible, _SpecificSQLExpressible) // - ==(_SpecificSQLExpressible, _SQLExpressible) // - ==(_SpecificSQLExpressible, _SpecificSQLExpressible) } extension _SpecificSQLExpressible where Self: _SQLOrdering { /// This property is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public var reversedSortDescriptor: _SQLSortDescriptor { return .Desc(sqlExpression) } /// This method is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public func orderingSQL(inout arguments: StatementArguments?) -> String { return sqlExpression.sql(&arguments) } } extension _SpecificSQLExpressible where Self: _SQLSelectable { /// This method is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public func resultColumnSQL(inout arguments: StatementArguments?) -> String { return sqlExpression.sql(&arguments) } /// This method is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public func countedSQL(inout arguments: StatementArguments?) -> String { return sqlExpression.sql(&arguments) } /// This property is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public var sqlSelectableKind: _SQLSelectableKind { return .Expression(sqlExpression) } } extension _SpecificSQLExpressible { /// Returns a value that can be used as an argument to FetchRequest.order() /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public var asc: _SQLSortDescriptor { return .Asc(sqlExpression) } /// Returns a value that can be used as an argument to FetchRequest.order() /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public var desc: _SQLSortDescriptor { return .Desc(sqlExpression) } /// Returns a value that can be used as an argument to FetchRequest.select() /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public func aliased(alias: String) -> _SQLSelectable { return _SQLResultColumn.Expression(expression: sqlExpression, alias: alias) } } /// This type is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public indirect enum _SQLExpression { /// For example: `name || 'rrr' AS pirateName` case Literal(String, StatementArguments?) /// For example: `1` or `'foo'` case Value(DatabaseValueConvertible?) // TODO: switch to DatabaseValue? /// For example: `name`, `table.name` case Identifier(identifier: String, sourceName: String?) /// For example: `name = 'foo' COLLATE NOCASE` case Collate(_SQLExpression, String) /// For example: `NOT condition` case Not(_SQLExpression) /// For example: `name = 'foo'` case Equal(_SQLExpression, _SQLExpression) /// For example: `name <> 'foo'` case NotEqual(_SQLExpression, _SQLExpression) /// For example: `name IS NULL` case Is(_SQLExpression, _SQLExpression) /// For example: `name IS NOT NULL` case IsNot(_SQLExpression, _SQLExpression) /// For example: `-value` case PrefixOperator(String, _SQLExpression) /// For example: `age + 1` case InfixOperator(String, _SQLExpression, _SQLExpression) /// For example: `id IN (1,2,3)` case In([_SQLExpression], _SQLExpression) /// For example `id IN (SELECT ...)` case InSubQuery(_SQLSelectQuery, _SQLExpression) /// For example `EXISTS (SELECT ...)` case Exists(_SQLSelectQuery) /// For example: `age BETWEEN 1 AND 2` case Between(value: _SQLExpression, min: _SQLExpression, max: _SQLExpression) /// For example: `LOWER(name)` case Function(String, [_SQLExpression]) /// For example: `COUNT(*)` case Count(_SQLSelectable) /// For example: `COUNT(DISTINCT name)` case CountDistinct(_SQLExpression) /// func sql(inout arguments: StatementArguments?) -> String { switch self { case .Literal(let sql, let literalArguments): if let literalArguments = literalArguments { guard arguments != nil else { fatalError("Not implemented") } arguments!.values.appendContentsOf(literalArguments.values) for (name, value) in literalArguments.namedValues { guard arguments!.namedValues[name] == nil else { fatalError("argument \(String(reflecting: name)) can't be reused") } arguments!.namedValues[name] = value } } return sql case .Value(let value): guard let value = value else { return "NULL" } if arguments == nil { return value.sqlLiteral } else { arguments!.values.append(value) return "?" } case .Identifier(let identifier, let sourceName): if let sourceName = sourceName { return sourceName.quotedDatabaseIdentifier + "." + identifier.quotedDatabaseIdentifier } else { return identifier.quotedDatabaseIdentifier } case .Collate(let expression, let collation): let sql = expression.sql(&arguments) let chars = sql.characters if chars.last! == ")" { return String(chars.prefixUpTo(chars.endIndex.predecessor())) + " COLLATE " + collation + ")" } else { return sql + " COLLATE " + collation } case .Not(let condition): switch condition { case .Not(let expression): return expression.sql(&arguments) case .In(let expressions, let expression): if expressions.isEmpty { return "1" } else { return "(" + expression.sql(&arguments) + " NOT IN (" + (expressions.map { $0.sql(&arguments) } as [String]).joinWithSeparator(", ") + "))" } case .InSubQuery(let subQuery, let expression): return "(" + expression.sql(&arguments) + " NOT IN (" + subQuery.sql(&arguments) + "))" case .Exists(let subQuery): return "(NOT EXISTS (" + subQuery.sql(&arguments) + "))" case .Equal(let lhs, let rhs): return _SQLExpression.NotEqual(lhs, rhs).sql(&arguments) case .NotEqual(let lhs, let rhs): return _SQLExpression.Equal(lhs, rhs).sql(&arguments) case .Is(let lhs, let rhs): return _SQLExpression.IsNot(lhs, rhs).sql(&arguments) case .IsNot(let lhs, let rhs): return _SQLExpression.Is(lhs, rhs).sql(&arguments) default: return "(NOT " + condition.sql(&arguments) + ")" } case .Equal(let lhs, let rhs): switch (lhs, rhs) { case (let lhs, .Value(let rhs)) where rhs == nil: // Swiftism! // Turn `filter(a == nil)` into `a IS NULL` since the intention is obviously to check for NULL. `a = NULL` would evaluate to NULL. return "(" + lhs.sql(&arguments) + " IS NULL)" case (.Value(let lhs), let rhs) where lhs == nil: // Swiftism! return "(" + rhs.sql(&arguments) + " IS NULL)" default: return "(" + lhs.sql(&arguments) + " = " + rhs.sql(&arguments) + ")" } case .NotEqual(let lhs, let rhs): switch (lhs, rhs) { case (let lhs, .Value(let rhs)) where rhs == nil: // Swiftism! // Turn `filter(a != nil)` into `a IS NOT NULL` since the intention is obviously to check for NULL. `a <> NULL` would evaluate to NULL. return "(" + lhs.sql(&arguments) + " IS NOT NULL)" case (.Value(let lhs), let rhs) where lhs == nil: // Swiftism! return "(" + rhs.sql(&arguments) + " IS NOT NULL)" default: return "(" + lhs.sql(&arguments) + " <> " + rhs.sql(&arguments) + ")" } case .Is(let lhs, let rhs): switch (lhs, rhs) { case (let lhs, .Value(let rhs)) where rhs == nil: return "(" + lhs.sql(&arguments) + " IS NULL)" case (.Value(let lhs), let rhs) where lhs == nil: return "(" + rhs.sql(&arguments) + " IS NULL)" default: return "(" + lhs.sql(&arguments) + " IS " + rhs.sql(&arguments) + ")" } case .IsNot(let lhs, let rhs): switch (lhs, rhs) { case (let lhs, .Value(let rhs)) where rhs == nil: return "(" + lhs.sql(&arguments) + " IS NOT NULL)" case (.Value(let lhs), let rhs) where lhs == nil: return "(" + rhs.sql(&arguments) + " IS NOT NULL)" default: return "(" + lhs.sql(&arguments) + " IS NOT " + rhs.sql(&arguments) + ")" } case .PrefixOperator(let SQLOperator, let value): return SQLOperator + value.sql(&arguments) case .InfixOperator(let SQLOperator, let lhs, let rhs): return "(" + lhs.sql(&arguments) + " \(SQLOperator) " + rhs.sql(&arguments) + ")" case .In(let expressions, let expression): guard !expressions.isEmpty else { return "0" } return "(" + expression.sql(&arguments) + " IN (" + (expressions.map { $0.sql(&arguments) } as [String]).joinWithSeparator(", ") + "))" case .InSubQuery(let subQuery, let expression): return "(" + expression.sql(&arguments) + " IN (" + subQuery.sql(&arguments) + "))" case .Exists(let subQuery): return "(EXISTS (" + subQuery.sql(&arguments) + "))" case .Between(value: let value, min: let min, max: let max): return "(" + value.sql(&arguments) + " BETWEEN " + min.sql(&arguments) + " AND " + max.sql(&arguments) + ")" case .Function(let functionName, let functionArguments): return functionName + "(" + (functionArguments.map { $0.sql(&arguments) } as [String]).joinWithSeparator(", ") + ")" case .Count(let counted): return "COUNT(" + counted.countedSQL(&arguments) + ")" case .CountDistinct(let expression): return "COUNT(DISTINCT " + expression.sql(&arguments) + ")" } } } extension _SQLExpression : _SpecificSQLExpressible { /// This property is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public var sqlExpression: _SQLExpression { return self } } extension _SQLExpression : _SQLSelectable {} extension _SQLExpression : _SQLOrdering {} // MARK: - _SQLSelectable /// This protocol is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public protocol _SQLSelectable { func resultColumnSQL(inout arguments: StatementArguments?) -> String func countedSQL(inout arguments: StatementArguments?) -> String var sqlSelectableKind: _SQLSelectableKind { get } } /// This type is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public enum _SQLSelectableKind { case Expression(_SQLExpression) case Star(sourceName: String?) } enum _SQLResultColumn { case Star(String?) case Expression(expression: _SQLExpression, alias: String) } extension _SQLResultColumn : _SQLSelectable { func resultColumnSQL(inout arguments: StatementArguments?) -> String { switch self { case .Star(let sourceName): if let sourceName = sourceName { return sourceName.quotedDatabaseIdentifier + ".*" } else { return "*" } case .Expression(expression: let expression, alias: let alias): return expression.sql(&arguments) + " AS " + alias.quotedDatabaseIdentifier } } func countedSQL(inout arguments: StatementArguments?) -> String { switch self { case .Star: return "*" case .Expression(expression: let expression, alias: _): return expression.sql(&arguments) } } var sqlSelectableKind: _SQLSelectableKind { switch self { case .Star(let sourceName): return .Star(sourceName: sourceName) case .Expression(expression: let expression, alias: _): return .Expression(expression) } } } // MARK: - SQLColumn /// A column in the database /// /// See https://github.com/groue/GRDB.swift#the-query-interface public struct SQLColumn { let sourceName: String? /// The name of the column public let name: String /// Initializes a column given its name. public init(_ name: String) { self.name = name self.sourceName = nil } init(_ name: String, sourceName: String?) { self.name = name self.sourceName = sourceName } } extension SQLColumn : _SpecificSQLExpressible { /// This property is an implementation detail of the query interface. /// Do not use it directly. /// /// See https://github.com/groue/GRDB.swift/#the-query-interface public var sqlExpression: _SQLExpression { return .Identifier(identifier: name, sourceName: sourceName) } } extension SQLColumn : _SQLSelectable {} extension SQLColumn : _SQLOrdering {}