/// The `ABS` SQL function. /// /// For example: /// /// ```swift /// // ABS(amount) /// abs(Column("amount")) /// ``` public func abs(_ value: some SQLSpecificExpressible) -> SQLExpression { .function("ABS", [value.sqlExpression]) } #if GRDBCUSTOMSQLITE || GRDBCIPHER /// The `AVG` SQL function. /// /// For example: /// /// ```swift /// // AVG(length) /// average(Column("length")) /// ``` public func average( _ value: some SQLSpecificExpressible, filter: (any SQLSpecificExpressible)? = nil) -> SQLExpression { .aggregateFunction("AVG", [value.sqlExpression], filter: filter?.sqlExpression) } #else /// The `AVG` SQL function. /// /// For example: /// /// ```swift /// // AVG(length) FILTER (WHERE length > 0) /// average(Column("length"), filter: Column("length") > 0) /// ``` @available(iOS 14, macOS 10.16, tvOS 14, watchOS 7, *) // SQLite 3.30+ public func average( _ value: some SQLSpecificExpressible, filter: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction( "AVG", [value.sqlExpression], filter: filter.sqlExpression) } /// The `AVG` SQL function. /// /// For example: /// /// ```swift /// // AVG(length) /// average(Column("length")) /// ``` public func average(_ value: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction("AVG", [value.sqlExpression]) } #endif /// The `CAST` SQL function. /// /// For example: /// /// ```swift /// // CAST(value AS REAL) /// cast(Column("value"), as: .real) /// ``` /// /// Related SQLite documentation: public func cast(_ expression: some SQLSpecificExpressible, as storageClass: Database.StorageClass) -> SQLExpression { .cast(expression.sqlExpression, as: storageClass) } /// The `COUNT` SQL function. /// /// For example: /// /// ```swift /// // COUNT(email) /// count(Column("email")) /// ``` public func count(_ counted: some SQLSpecificExpressible) -> SQLExpression { .count(counted.sqlExpression) } /// The `COUNT(DISTINCT)` SQL function. /// /// For example: /// /// ```swift /// // COUNT(DISTINCT email) /// count(distinct: Column("email")) /// ``` public func count(distinct value: some SQLSpecificExpressible) -> SQLExpression { .countDistinct(value.sqlExpression) } extension SQLSpecificExpressible { /// The `IFNULL` SQL function. /// /// For example: /// /// ```swift /// // IFNULL(name, 'Anonymous') /// Column("name") ?? "Anonymous" /// ``` public static func ?? (lhs: Self, rhs: some SQLExpressible) -> SQLExpression { .function("IFNULL", [lhs.sqlExpression, rhs.sqlExpression]) } } /// The `LENGTH` SQL function. /// /// For example: /// /// ```swift /// // LENGTH(name) /// length(Column("name")) /// ``` public func length(_ value: some SQLSpecificExpressible) -> SQLExpression { .function("LENGTH", [value.sqlExpression]) } #if GRDBCUSTOMSQLITE || GRDBCIPHER /// The `MAX` SQL function. /// /// For example: /// /// ```swift /// // MAX(score) /// max(Column("score")) /// ``` public func max( _ value: some SQLSpecificExpressible, filter: (any SQLSpecificExpressible)? = nil) -> SQLExpression { .aggregateFunction("MAX", [value.sqlExpression], filter: filter?.sqlExpression) } #else /// The `MAX` SQL function. /// /// For example: /// /// ```swift /// // MAX(score) FILTER (WHERE score < 0) /// max(Column("score"), filter: Column("score") < 0) /// ``` @available(iOS 14, macOS 10.16, tvOS 14, watchOS 7, *) // SQLite 3.30+ public func max( _ value: some SQLSpecificExpressible, filter: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction("MAX", [value.sqlExpression], filter: filter.sqlExpression) } /// The `MAX` SQL function. /// /// For example: /// /// ```swift /// // MAX(score) /// max(Column("score")) /// ``` public func max(_ value: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction("MAX", [value.sqlExpression]) } #endif #if GRDBCUSTOMSQLITE || GRDBCIPHER /// The `MIN` SQL function. /// /// For example: /// /// ```swift /// // MIN(score) /// min(Column("score")) /// ``` public func min( _ value: some SQLSpecificExpressible, filter: (any SQLSpecificExpressible)? = nil) -> SQLExpression { .aggregateFunction("MIN", [value.sqlExpression], filter: filter?.sqlExpression) } #else /// The `MIN` SQL function. /// /// For example: /// /// ```swift /// // MIN(score) FILTER (WHERE score > 0) /// min(Column("score"), filter: Column("score") > 0) /// ``` @available(iOS 14, macOS 10.16, tvOS 14, watchOS 7, *) // SQLite 3.30+ public func min( _ value: some SQLSpecificExpressible, filter: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction("MIN", [value.sqlExpression], filter: filter.sqlExpression) } /// The `MIN` SQL function. /// /// For example: /// /// ```swift /// // MIN(score) /// min(Column("score")) /// ``` public func min(_ value: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction("MIN", [value.sqlExpression]) } #endif #if GRDBCUSTOMSQLITE || GRDBCIPHER /// The `SUM` SQL function. /// /// For example: /// /// ```swift /// // SUM(amount) /// sum(Column("amount")) /// ``` /// /// See also ``total(_:)``. /// /// Related SQLite documentation: . public func sum( _ value: some SQLSpecificExpressible, orderBy ordering: (any SQLOrderingTerm)? = nil, filter: (any SQLSpecificExpressible)? = nil) -> SQLExpression { .aggregateFunction( "SUM", [value.sqlExpression], ordering: ordering?.sqlOrdering, filter: filter?.sqlExpression) } #else /// The `SUM` SQL function. /// /// For example: /// /// ```swift /// // SUM(amount) FILTER (WHERE amount > 0) /// sum(Column("amount"), filter: Column("amount") > 0) /// ``` /// /// See also ``total(_:)``. /// /// Related SQLite documentation: . @available(iOS 14, macOS 10.16, tvOS 14, watchOS 7, *) // SQLite 3.30+ public func sum( _ value: some SQLSpecificExpressible, filter: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction( "SUM", [value.sqlExpression], filter: filter.sqlExpression) } /// The `SUM` SQL function. /// /// For example: /// /// ```swift /// // SUM(amount) /// sum(Column("amount")) /// ``` /// /// See also ``total(_:)``. /// /// Related SQLite documentation: . public func sum(_ value: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction("SUM", [value.sqlExpression]) } #endif #if GRDBCUSTOMSQLITE || GRDBCIPHER /// The `TOTAL` SQL function. /// /// For example: /// /// ```swift /// // TOTAL(amount) /// total(Column("amount")) /// ``` /// /// See also ``sum(_:)``. /// /// Related SQLite documentation: . public func total( _ value: some SQLSpecificExpressible, orderBy ordering: (any SQLOrderingTerm)? = nil, filter: (any SQLSpecificExpressible)? = nil) -> SQLExpression { .aggregateFunction( "TOTAL", [value.sqlExpression], ordering: ordering?.sqlOrdering, filter: filter?.sqlExpression) } #else /// The `TOTAL` SQL function. /// /// For example: /// /// ```swift /// // TOTAL(amount) FILTER (WHERE amount > 0) /// total(Column("amount"), filter: Column("amount") > 0) /// ``` /// /// See also ``total(_:)``. /// /// Related SQLite documentation: . @available(iOS 14, macOS 10.16, tvOS 14, watchOS 7, *) // SQLite 3.30+ public func total( _ value: some SQLSpecificExpressible, filter: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction( "TOTAL", [value.sqlExpression], filter: filter.sqlExpression) } /// The `TOTAL` SQL function. /// /// For example: /// /// ```swift /// // TOTAL(amount) /// total(Column("amount")) /// ``` /// /// See also ``sum(_:)``. /// /// Related SQLite documentation: . public func total(_ value: some SQLSpecificExpressible) -> SQLExpression { .aggregateFunction("TOTAL", [value.sqlExpression]) } #endif // MARK: - String functions extension SQLSpecificExpressible { /// An SQL expression that calls the Foundation /// `String.capitalized` property. /// /// For example: /// /// ```swift /// Column("name").capitalized /// ``` public var capitalized: SQLExpression { DatabaseFunction.capitalize(sqlExpression) } /// An SQL expression that calls the Swift /// `String.lowercased()` method. /// /// For example: /// /// ```swift /// Column("name").lowercased /// ``` public var lowercased: SQLExpression { DatabaseFunction.lowercase(sqlExpression) } /// An SQL expression that calls the Swift /// `String.uppercased()` method. /// /// For example: /// /// ```swift /// Column("name").uppercased /// ``` public var uppercased: SQLExpression { DatabaseFunction.uppercase(sqlExpression) } } extension SQLSpecificExpressible { /// An SQL expression that calls the Foundation /// `String.localizedCapitalized` property. /// /// For example: /// /// ```swift /// Column("name").localizedCapitalized /// ``` public var localizedCapitalized: SQLExpression { DatabaseFunction.localizedCapitalize(sqlExpression) } /// An SQL expression that calls the Foundation /// `String.localizedLowercase` property. /// /// For example: /// /// ```swift /// Column("name").localizedLowercased /// ``` public var localizedLowercased: SQLExpression { DatabaseFunction.localizedLowercase(sqlExpression) } /// An SQL expression that calls the Foundation /// `String.localizedUppercase` property. /// /// For example: /// /// ```swift /// Column("name").localizedUppercased /// ``` public var localizedUppercased: SQLExpression { DatabaseFunction.localizedUppercase(sqlExpression) } } // MARK: - Date functions /// A date modifier for SQLite date functions. /// /// Related SQLite documentation: public enum SQLDateModifier: SQLSpecificExpressible, Sendable { /// Adds the specified amount of seconds case second(Double) /// Adds the specified amount of minutes case minute(Int) /// Adds the specified amount of hours case hour(Int) /// Adds the specified amount of days case day(Int) /// Adds the specified amount of months case month(Int) /// Adds the specified amount of years case year(Int) /// Shifts the date backwards to the beginning of the current day case startOfDay /// Shifts the date backwards to the beginning of the current month case startOfMonth /// Shifts the date backwards to the beginning of the current year case startOfYear /// See case weekday(Int) /// See case unixEpoch /// See case localTime /// See case utc public var sqlExpression: SQLExpression { rawValue.sqlExpression } var rawValue: String { switch self { case let .day(value): return "\(value) days" case let .hour(value): return "\(value) hours" case let .minute(value): return "\(value) minutes" case let .second(value): return "\(value) seconds" case let .month(value): return "\(value) months" case let .year(value): return "\(value) years" case .startOfMonth: return "start of month" case .startOfYear: return "start of year" case .startOfDay: return "start of day" case let .weekday(value): return "weekday \(value)" case .unixEpoch: return "unixepoch" case .localTime: return "localtime" case .utc: return "utc" } } } /// The `JULIANDAY` SQL function. /// /// For example: /// /// ```swift /// // JULIANDAY(date) /// julianDay(Column("date")) /// /// // JULIANDAY(date, '1 days') /// julianDay(Column("date"), .day(1)) /// ``` /// /// Related SQLite documentation: public func julianDay(_ value: some SQLSpecificExpressible, _ modifiers: SQLDateModifier...) -> SQLExpression { .function("JULIANDAY", [value.sqlExpression] + modifiers.map(\.sqlExpression)) } // MARK: DATETIME(...) /// The `DATETIME` SQL function. /// /// For example: /// /// ```swift /// // DATETIME(date) /// dateTime(Column("date")) /// /// // DATETIME(date, '1 days') /// dateTime(Column("date"), .day(1)) /// ``` /// /// Related SQLite documentation: public func dateTime(_ value: some SQLSpecificExpressible, _ modifiers: SQLDateModifier...) -> SQLExpression { .function("DATETIME", [value.sqlExpression] + modifiers.map(\.sqlExpression)) }