所以我正在使用swift中的sql数据库抽象层,我想尽可能安全地编写它。我的意思是,我宁愿让任何人都无法使用我的库在数据库中做任何非法行为。
我还无法完全解决的一件事是如何使从Swift类型到SQL数据类型的转换100%安全。所以我将解释我目前的实施及其缺陷:
因此在SQL中,许多数据类型都有参数。例如,如果要将列定义为VARCHAR
,则需要为其指定VARCHAR
的最大长度参数,例如VARCHAR(255)
。您可以说VARCHAR
是SQL的原始数据类型之一,VARCHAR(255)
是更多指定的数据类型。为了在swift中以类型安全的方式表示,我创建了两个协议:
public protocol PrimitiveDataType {
associatedtype Options = Void
}
public protocol SpecifiedDataType {
associatedtype Primitive: PrimitiveDataType
static var options: Primitive.Options { get }
static func from(primitive: Primitive) -> Self
var primitive: Primitive { get }
}
所以这是一个PrimitiveDataType
的例子:
extension String: PrimitiveDataType {
public enum DatabaseStringType {
case char(length: Int), varchar(limit: Int), text
}
public typealias Options = DatabaseStringType
}
以下是SpecifiedDataType
:
struct Name {
let value: String
init?(_ value: String) {
guard case 0...50 = value.characters.count else {
return nil
}
self.value = value
}
}
extension Name: SpecifiedDataType {
static let options = String.DatabaseStringType.varchar(limit: 50)
static func from(primitive: String) -> Name {
return Name(primitive)!
}
var primitive: String {
return value
}
}
现在,我可以使用库中其他位置的信息来了解每当请求Name
类型时预期的数据库列类型。这使我的库能够确保数据库列的类型始终正确。
我还没有编写所有代码,但它可能看起来像这样:
func createColumn<SDT: SpecifiedDataType>(ofType type: SDT) -> String {
switch SDT.options {
case let options as String.DatabaseStringType:
switch options {
case .text:
return "TEXT"
case .char(let length):
return "CHAR(\(length))"
case .varchar(let limit):
return "VARCHAR(\(limit))"
}
case let length as UInt32.Options:
// return something like UNSIGNED INTEGER(\(length)) or whatever
// case etcetera
}
}
这只有一个小问题。有效的原始数据类型集是有限的,但PrimitiveDataType
协议的可能实现集是无限制的,因为我无法阻止任何人创建自己的协议实现。
因此,最好使用某种枚举而不是协议的多种实现。因为没有人可以扩展我创建的枚举,所以我可以将选项限制为我定义为有效类型的任何内容。但是,枚举会产生另一个在我当前实现中不存在的问题。
您可以在我当前的实现中看到,每当有人实现SpecifiedDataType
时,其定义的选项如下:
static let options = String.DatabaseStringType.varchar(limit: 50)
我可以相信编译器会强制它们通过实现from(primitive: String)
方法和primitive: String
(计算)变量使其类型与字符串兼容。 AFAIK,如果我为enum切换协议,我将失去编译器强制的类型安全性。
总而言之,我希望拥有以下所有内容:
到目前为止,我只知道如何做前两个,但不是最后一个,或最后一个,而不是前两个。我怎么得到这三个?