【发布时间】:2019-08-29 10:06:36
【问题描述】:
我有一个类可以使用函数生成 SQLite 查询,这些函数可以将一个连接到另一个看起来像一个“本机”SQL 语句。
这是当前工作的协议:
/// Protocol for any object directly related with a database table.
public protocol Table {
/// Generic enum implementing the table columns.
associatedtype Columns: (RawRepresentable & CodingKey & CaseIterable & Hashable)
/// The name of the table that will be represented in the entity.
/// Could be declarated as let in the struct that implements this protocol.
static var tablename: String { get }
}
这里是一个实现 Table 协议的结构
public struct TMAEVersion : Table {
/// Properties
public var statusMobile: String?
public var version: String?
/// Overriding the default name to account for the special name of the table
public var tablename: String = "TMAEVersion"
/// Table columns keys
public enum CodingKeys : String, CodingKey, CaseIterable {
case statusMobile = "status_mobile"
case version = "Version"
}
public typealias Columns = CodingKeys
}
这是当前使用 Table 协议实现功能的 Query 类:
public class Query<T> {
// MARK: Properties
public var columns = [String]()
public var table: String = ""
public var literal: String = ""
fileprivate var showLogs: Bool = true
// MARK: Init
public init(literal: String) {
self.literal = literal
}
/// Empty init for normal queries that don't take a literal
public init(showingLogs: Bool? = nil) {
if let showingLogs = showingLogs { showLogs = showingLogs }
}
}
public extension Query where T: Table {
// MARK: Select
func generateSelect(_ distinct: Bool? = nil , _ columns: [String], from tablename: String) -> Query {
let statement = Select(distinct: distinct ?? false, columns: columns)
self.columns = statement.columns
self.table = tablename
self.literal += statement.sentence
return self
}
func select(distinct: Bool? = nil, _ columns: CodingKey...) -> Query {
return generateSelect(distinct ?? false, columns.map { $0.stringValue }, from: T.tablename)
}
func select(distinct: Bool? = nil, _ columns: T.Columns...) -> Query {
return generateSelect(distinct ?? false, columns.map { $0.stringValue }, from: T.tablename)
}
/// Note: Comparator and Operator are enums containing cases like:
/// - Comparator: equal, diff, greaterThan...
/// - Operator: and, or...
func generateWhere(_ col: String, _ comp: Comparator, _ val: Any, _ op: Operator?) -> Query {
let statement = Where(column: col, value: val, comparator: comp, operator: op)
self.literal += statement.sentence
return self
}
func `where`(_ lc: CodingKey, _ comp: Comparator, _ rc: CodingKey) -> Query {
return generateWhere(column, comp, value, nil)
}
}
工作示例:
public func currentVersion() -> String? {
return Query<TMAEVersion>()
.select(.Version)
.order(by: .Version)
.execute().first?
.Version
}
我想避免做Query<SomeTable>() 的需要,所以我尝试的是这个(并且它是出现错误的地方):
func select<T: Table>(distinct: Bool?, columns: [T.Columns]) -> Query {
// Code...
}
错误显示:“函数签名中未使用通用参数'T'”。
我知道这样做可以解决问题,但是我需要避免参数from: T.Type,我不知道该怎么办。
func select<T: Table>(from: T.Type, distinct: Bool?, columns: [T.Columns]) -> Query
除了我尝试在 init() 函数中传递 Table 协议,但它需要有一个属性,所以......问题仍然存在。
有什么想法吗?
已编辑:添加示例和实现
【问题讨论】:
-
@JoakimDanielson 它目前在我的代码中返回
-> Query。工作功能就像Query<SomeTable>().select(.field1, .filed2).where(.field3, .equal, 1).execute() -
那么您在类 Query 中有一个返回 Query 实例的函数?那么它不应该被声明为静态的吗?我必须说,很难理解你想用这段代码完成什么。
-
完全不清楚为什么 Table 是一个协议,更不用说为什么它是一个通用协议。请展示您正在尝试做的具体示例。什么是特定的查询和表?然后你想概括什么,为什么?
-
@JoakimDanielson 到目前为止,我已经完成了生成连接函数的 SQLite 查询,如示例中所示。但是我现在想要完成的是在没有 的情况下生成它们,只是将它传递给参数,或者如果可能的话,以某种方式传递给构造函数。
-
@matt Table 是一个协议,因为我创建了许多需要符合表名和列的结构。我用一些例子编辑了这篇文章。
标签: swift generics protocols swift-protocols