526 lines
17 KiB
Swift
526 lines
17 KiB
Swift
extension SQLSpecificExpressible {
|
|
// MARK: - Egality and Identity Operators (=, <>, IS, IS NOT)
|
|
|
|
/// Compares two SQL expressions.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // name = 'Arthur'
|
|
/// Column("name") == "Arthur"
|
|
/// ```
|
|
///
|
|
/// When the right operand is nil, `IS NULL` is used instead of the
|
|
/// `=` operator:
|
|
///
|
|
/// ```swift
|
|
/// // name IS NULL
|
|
/// Column("name") == nil
|
|
/// ```
|
|
public static func == (lhs: Self, rhs: (any SQLExpressible)?) -> SQLExpression {
|
|
.equal(lhs.sqlExpression, rhs?.sqlExpression ?? .null)
|
|
}
|
|
|
|
/// The `=` SQL operator.
|
|
public static func == (lhs: Self, rhs: Bool) -> SQLExpression {
|
|
if rhs {
|
|
return lhs.sqlExpression.is(.true)
|
|
} else {
|
|
return lhs.sqlExpression.is(.false)
|
|
}
|
|
}
|
|
|
|
/// Compares two SQL expressions.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // 'Arthur' = name
|
|
/// "Arthur" == Column("name")
|
|
/// ```
|
|
///
|
|
/// When the left operand is nil, `IS NULL` is used instead of the
|
|
/// `=` operator:
|
|
///
|
|
/// ```swift
|
|
/// // name IS NULL
|
|
/// nil == Column("name")
|
|
/// ```
|
|
public static func == (lhs: (any SQLExpressible)?, rhs: Self) -> SQLExpression {
|
|
.equal(lhs?.sqlExpression ?? .null, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `=` SQL operator.
|
|
public static func == (lhs: Bool, rhs: Self) -> SQLExpression {
|
|
if lhs {
|
|
return rhs.sqlExpression.is(.true)
|
|
} else {
|
|
return rhs.sqlExpression.is(.false)
|
|
}
|
|
}
|
|
|
|
/// The `=` SQL operator.
|
|
public static func == (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.equal(lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// Compares two SQL expressions.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // name <> 'Arthur'
|
|
/// Column("name") != "Arthur"
|
|
/// ```
|
|
///
|
|
/// When the right operand is nil, `IS NOT NULL` is used instead of the
|
|
/// `<>` operator:
|
|
///
|
|
/// ```swift
|
|
/// // name IS NOT NULL
|
|
/// Column("name") != nil
|
|
/// ```
|
|
public static func != (lhs: Self, rhs: (any SQLExpressible)?) -> SQLExpression {
|
|
!(lhs == rhs)
|
|
}
|
|
|
|
/// The `<>` SQL operator.
|
|
public static func != (lhs: Self, rhs: Bool) -> SQLExpression {
|
|
!(lhs == rhs)
|
|
}
|
|
|
|
/// Compares two SQL expressions.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // 'Arthur' <> name
|
|
/// "Arthur" != Column("name")
|
|
/// ```
|
|
///
|
|
/// When the left operand is nil, `IS NOT NULL` is used instead of the
|
|
/// `<>` operator:
|
|
///
|
|
/// ```swift
|
|
/// // name IS NOT NULL
|
|
/// nil != Column("name")
|
|
/// ```
|
|
public static func != (lhs: (any SQLExpressible)?, rhs: Self) -> SQLExpression {
|
|
!(lhs == rhs)
|
|
}
|
|
|
|
/// The `<>` SQL operator.
|
|
public static func != (lhs: Bool, rhs: Self) -> SQLExpression {
|
|
!(lhs == rhs)
|
|
}
|
|
|
|
/// The `<>` SQL operator.
|
|
public static func != (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
!(lhs == rhs)
|
|
}
|
|
|
|
/// The `IS` SQL operator.
|
|
public static func === (lhs: Self, rhs: (any SQLExpressible)?) -> SQLExpression {
|
|
.compare(.is, lhs.sqlExpression, rhs?.sqlExpression ?? .null)
|
|
}
|
|
|
|
/// The `IS` SQL operator.
|
|
public static func === (lhs: (any SQLExpressible)?, rhs: Self) -> SQLExpression {
|
|
if let lhs {
|
|
return .compare(.is, lhs.sqlExpression, rhs.sqlExpression)
|
|
} else {
|
|
return .compare(.is, rhs.sqlExpression, .null)
|
|
}
|
|
}
|
|
|
|
/// The `IS` SQL operator.
|
|
public static func === (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.compare(.is, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `IS NOT` SQL operator.
|
|
public static func !== (lhs: Self, rhs: (any SQLExpressible)?) -> SQLExpression {
|
|
!(lhs === rhs)
|
|
}
|
|
|
|
/// The `IS NOT` SQL operator.
|
|
public static func !== (lhs: (any SQLExpressible)?, rhs: Self) -> SQLExpression {
|
|
!(lhs === rhs)
|
|
}
|
|
|
|
/// The `IS NOT` SQL operator.
|
|
public static func !== (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
!(lhs === rhs)
|
|
}
|
|
|
|
// MARK: - Comparison Operators (<, >, <=, >=)
|
|
|
|
/// The `<` SQL operator.
|
|
public static func < (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.binary(.lessThan, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `<` SQL operator.
|
|
public static func < (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.binary(.lessThan, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `<` SQL operator.
|
|
public static func < (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.binary(.lessThan, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `<=` SQL operator.
|
|
public static func <= (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.binary(.lessThanOrEqual, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `<=` SQL operator.
|
|
public static func <= (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.binary(.lessThanOrEqual, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `<=` SQL operator.
|
|
public static func <= (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.binary(.lessThanOrEqual, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `>` SQL operator.
|
|
public static func > (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.binary(.greaterThan, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `>` SQL operator.
|
|
public static func > (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.binary(.greaterThan, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `>` SQL operator.
|
|
public static func > (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.binary(.greaterThan, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `>=` SQL operator.
|
|
public static func >= (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.binary(.greaterThanOrEqual, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `>=` SQL operator.
|
|
public static func >= (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.binary(.greaterThanOrEqual, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `>=` SQL operator.
|
|
public static func >= (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.binary(.greaterThanOrEqual, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
}
|
|
|
|
// MARK: - Inclusion Operators (BETWEEN, IN)
|
|
|
|
extension Range where Bound: SQLExpressible {
|
|
/// Returns an SQL expression that checks the inclusion of an expression in
|
|
/// a range.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // email >= 'A' AND email < 'B'
|
|
/// ("A"..<"B").contains(Column("email"))
|
|
/// ```
|
|
public func contains(_ element: some SQLSpecificExpressible) -> SQLExpression {
|
|
(element >= lowerBound) && (element < upperBound)
|
|
}
|
|
}
|
|
|
|
extension ClosedRange where Bound: SQLExpressible {
|
|
/// Returns an SQL expression that checks the inclusion of an expression in
|
|
/// a range.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // initial BETWEEN 'A' AND 'B'
|
|
/// ("A"..."B").contains(Column("initial"))
|
|
/// ```
|
|
public func contains(_ element: some SQLSpecificExpressible) -> SQLExpression {
|
|
.between(
|
|
expression: element.sqlExpression,
|
|
lowerBound: lowerBound.sqlExpression,
|
|
upperBound: upperBound.sqlExpression)
|
|
}
|
|
}
|
|
|
|
extension CountableRange where Bound: SQLExpressible {
|
|
/// Returns an SQL expression that checks the inclusion of an expression in
|
|
/// a range.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // id >= 1 AND id < 10
|
|
/// (1..<10).contains(Column("id"))
|
|
/// ```
|
|
public func contains(_ element: some SQLSpecificExpressible) -> SQLExpression {
|
|
(element >= lowerBound) && (element < upperBound)
|
|
}
|
|
}
|
|
|
|
extension CountableClosedRange where Bound: SQLExpressible {
|
|
/// Returns an SQL expression that checks the inclusion of an expression in
|
|
/// a range.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // id BETWEEN 1 AND 10
|
|
/// (1...10).contains(Column("id"))
|
|
/// ```
|
|
public func contains(_ element: some SQLSpecificExpressible) -> SQLExpression {
|
|
.between(
|
|
expression: element.sqlExpression,
|
|
lowerBound: lowerBound.sqlExpression,
|
|
upperBound: upperBound.sqlExpression)
|
|
}
|
|
}
|
|
|
|
extension Sequence where Element: SQLExpressible {
|
|
/// Returns an SQL expression that checks the inclusion of an expression in
|
|
/// a sequence.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // id IN (1,2,3)
|
|
/// [1, 2, 3].contains(Column("id"))
|
|
/// ```
|
|
public func contains(_ element: some SQLSpecificExpressible) -> SQLExpression {
|
|
SQLCollection.array(map(\.sqlExpression)).contains(element.sqlExpression)
|
|
}
|
|
}
|
|
|
|
extension Sequence where Element == any SQLExpressible {
|
|
/// Returns an SQL expression that checks the inclusion of an expression in
|
|
/// a sequence.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // id IN (1,2,3)
|
|
/// [1, 2, 3].contains(Column("id"))
|
|
/// ```
|
|
public func contains(_ element: some SQLSpecificExpressible) -> SQLExpression {
|
|
SQLCollection.array(map(\.sqlExpression)).contains(element.sqlExpression)
|
|
}
|
|
}
|
|
|
|
|
|
// MARK: - Arithmetic Operators (+, -, *, /)
|
|
|
|
extension SQLSpecificExpressible {
|
|
/// The `*` SQL operator.
|
|
public static func * (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.associativeBinary(.multiply, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `*` SQL operator.
|
|
public static func * (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.associativeBinary(.multiply, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `*` SQL operator.
|
|
public static func * (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.associativeBinary(.multiply, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `/` SQL operator.
|
|
public static func / (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.binary(.divide, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `/` SQL operator.
|
|
public static func / (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.binary(.divide, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `/` SQL operator.
|
|
public static func / (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.binary(.divide, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `+` SQL operator.
|
|
public static func + (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.associativeBinary(.add, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `+` SQL operator.
|
|
public static func + (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.associativeBinary(.add, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `+` SQL operator.
|
|
public static func + (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.associativeBinary(.add, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `-` SQL operator.
|
|
public static prefix func - (value: Self) -> SQLExpression {
|
|
.unary(.minus, value.sqlExpression)
|
|
}
|
|
|
|
/// The `-` SQL operator.
|
|
public static func - (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.binary(.subtract, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `-` SQL operator.
|
|
public static func - (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.binary(.subtract, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `-` SQL operator.
|
|
public static func - (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.binary(.subtract, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
|
|
// MARK: - Logical Operators (AND, OR, NOT)
|
|
|
|
/// The `AND` SQL operator.
|
|
public static func && (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.associativeBinary(.and, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `AND` SQL operator.
|
|
public static func && (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.associativeBinary(.and, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `AND` SQL operator.
|
|
public static func && (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.associativeBinary(.and, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `OR` SQL operator.
|
|
public static func || (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.associativeBinary(.or, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `OR` SQL operator.
|
|
public static func || (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.associativeBinary(.or, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `OR` SQL operator.
|
|
public static func || (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.associativeBinary(.or, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// A negated logical SQL expression.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // NOT isBlue
|
|
/// !Column("isBlue")
|
|
/// ```
|
|
///
|
|
/// Some expressions are negated with specific SQL operators:
|
|
///
|
|
/// ```swift
|
|
/// // id NOT BETWEEN 1 AND 10
|
|
/// !((1...10).contains(Column("id")))
|
|
/// ```
|
|
public static prefix func ! (value: Self) -> SQLExpression {
|
|
value.sqlExpression.is(.falsey)
|
|
}
|
|
}
|
|
|
|
// MARK: - Bitwise Operators (&, |, ~, <<, >>)
|
|
|
|
extension SQLSpecificExpressible {
|
|
/// The `&` SQL operator.
|
|
public static func & (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.associativeBinary(.bitwiseAnd, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `&` SQL operator.
|
|
public static func & (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.associativeBinary(.bitwiseAnd, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `&` SQL operator.
|
|
public static func & (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.associativeBinary(.bitwiseAnd, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `|` SQL operator.
|
|
public static func | (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.associativeBinary(.bitwiseOr, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `|` SQL operator.
|
|
public static func | (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.associativeBinary(.bitwiseOr, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `|` SQL operator.
|
|
public static func | (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.associativeBinary(.bitwiseOr, [lhs.sqlExpression, rhs.sqlExpression])
|
|
}
|
|
|
|
/// The `<<` SQL operator.
|
|
public static func << (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.binary(.leftShift, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `<<` SQL operator.
|
|
public static func << (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.binary(.leftShift, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `<<` SQL operator.
|
|
public static func << (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.binary(.leftShift, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `>>` SQL operator.
|
|
public static func >> (lhs: Self, rhs: some SQLExpressible) -> SQLExpression {
|
|
.binary(.rightShift, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `>>` SQL operator.
|
|
public static func >> (lhs: some SQLExpressible, rhs: Self) -> SQLExpression {
|
|
.binary(.rightShift, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `>>` SQL operator.
|
|
public static func >> (lhs: Self, rhs: some SQLSpecificExpressible) -> SQLExpression {
|
|
.binary(.rightShift, lhs.sqlExpression, rhs.sqlExpression)
|
|
}
|
|
|
|
/// The `~` SQL operator.
|
|
public static prefix func ~ (value: Self) -> SQLExpression {
|
|
.unary(.bitwiseNot, value.sqlExpression)
|
|
}
|
|
}
|
|
|
|
// MARK: - Like Operator
|
|
|
|
extension SQLSpecificExpressible {
|
|
/// The `LIKE` SQL operator.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// ```swift
|
|
/// // email LIKE '%@example.com"
|
|
/// Column("email").like("%@example.com")
|
|
///
|
|
/// // title LIKE '%10\%%' ESCAPE '\'
|
|
/// Column("title").like("%10\\%%", escape: "\\")
|
|
/// ```
|
|
public func like(_ pattern: some SQLExpressible, escape: (any SQLExpressible)? = nil) -> SQLExpression {
|
|
.escapableBinary(.like, sqlExpression, pattern.sqlExpression, escape: escape?.sqlExpression)
|
|
}
|
|
}
|