Eve*_*ert 5 enums type-safety swift
所以我正在使用swift中的sql数据库抽象层,我希望尽可能安全地编写它.我的意思是,我宁愿让任何人都无法使用我的库在数据库中做任何非法行为.
我还无法完全解决的一件事是如何使从Swift类型到SQL数据类型的转换100%安全.所以我将解释我目前的实现及其缺陷:
所以在SQL中,许多数据类型都有参数.例如,当您要将列定义为a时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 }
}
Run Code Online (Sandbox Code Playgroud)
所以这是一个例子PrimitiveDataType
:
extension String: PrimitiveDataType {
public enum DatabaseStringType {
case char(length: Int), varchar(limit: Int), text
}
public typealias Options = DatabaseStringType
}
Run Code Online (Sandbox Code Playgroud)
这是一个例子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
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我可以使用库中其他位置的信息来了解每当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
}
}
Run Code Online (Sandbox Code Playgroud)
这只有一个小问题.有效的原始数据类型集是有限的,但PrimitiveDataType
协议的可能实现集是无限的,因为我无法阻止任何人创建自己的协议实现.
因此,出于这个原因,最好使用某种枚举而不是协议的许多实现.因为没有人可以扩展我创建的枚举,所以我可以将选项限制为我定义为有效类型的任何内容.但是,枚举会产生另一个在我当前实现中不存在的问题.
您可以在我当前的实现中看到,每当有人实现SpecifiedDataType
其定义的选项时,如下所示:
static let options = String.DatabaseStringType.varchar(limit: 50)
Run Code Online (Sandbox Code Playgroud)
我相信编译器会强制它们通过实现from(primitive: String)
方法和primitive: String
(计算)变量使其类型与字符串兼容.AFAIK,如果我为枚举切换协议,我将失去编译器强制的类型安全性.
总而言之,我希望拥有以下所有内容:
到目前为止,我只知道如何做前两个,但不是最后一个,或最后一个,而不是前两个.我怎么得到这三个?
归档时间: |
|
查看次数: |
293 次 |
最近记录: |