语句 (Statement)

用于编写 SQL 语句的 Swift DSL。

使用 Swift 编写 SQL 🤯

let expressionId: Int = 123
let languageCode: LanguageCode? = .en
let regionCode: RegionCode? = .us

let statement = SQLiteStatement(
    .SELECT(
        .column(Translation["id"]!),
        .column(Translation["expression_id"]!),
        .column(Translation["language_code"]!),
        .column(Translation["region_code"]!),
        .column(Translation["value"]!)
    ),
    .FROM_TABLE(Translation.self),
    .WHERE(
        .AND(
            .comparison(Translation.expressionID, .equal(expressionID)),
            .unwrap(languageCode, transform: { .comparison(Translation["language_code"]!, .equal($0.rawValue)) }),
            .unwrap(regionCode, transform: { .comparison(Translation["region_code"]!, .equal($0.rawValue)) }),
            .if(languageCode != nil && regionCode == nil, .logical(Translation.region, .isNull))
        )
    )
)

statement 的第一部分应该清晰明了

SELECT translation.id, translation.expression_id, translation.language_code, translation.region_code, translation.value
FROM translation
...

但是,请仔细查看 .AND 块中提供的元素。languageCoderegionCode 都是可选的,当其中一个为 nil 时,还有一个额外的逻辑元素子句。考虑到所有可选参数和逻辑,有可能生成 4 个独立的 where 子句。

WHERE translation.expression_id = 123
---
WHERE translation.expression_id = 123 AND translation.language_code = 'en' AND translation.region_code IS NULL
---
WHERE translation.expression_id = 123 AND translation.region_code = 'US'
---
WHERE translation.expression_id = 123 AND translation.language_code = 'en' AND translation.region_code = 'US'

类型安全魔法

struct Translation: Entity, Identifiable {

    let tableName: String = "translation"

    /// Unique/Primary Key
    @Field("id", unique: true, primaryKey: true, autoIncrement: true)
    var id: Int = 0

    /// Expression (Foreign Key)
    @Field("expression_id", foreignKey: .init("expression", "id"))
    var expressionID: Expression.ID = 0

    /// Language of the translation
    @Field("language_code")
    var language: String = LanguageCode.default.rawValue

    /// Region code specifier
    @Field("region_code")
    var region: String? = nil

    /// The translated string
    @Field("value")
    var value: String = ""
}

自动魔法 Epoxy

使用 Swift 反射 API Mirror@Field 属性会被自动合成。

extension Entity {
    var attributes: [Attribute] {
        var _columns: [Attribute] = []
        
        let mirror = Mirror(reflecting: self)
        for child in mirror.children {
            if let column = child.value as? AttributeConvertible {
                _columns.append(column.attribute)
            } else if let column = child.value as? Attribute {
                _columns.append(column)
            }
        }
        
        return _columns
    }
}

安装

Statement 通过 Swift 包管理器 分发。要将其安装到项目中,请将其作为依赖项添加到您的 Package.swift 清单文件中。

let package = Package(
    ...
    dependencies: [
        .package(url: "https://github.com/richardpiazza/Statement.git", .upToNextMinor(from: "0.8.0")
    ],
    ...
)

然后,在您想要使用它的任何地方导入 Statement

import Statement