Tim*_*ean 5 vapor vapor-fluent
我正在尝试使用 Repository 模式将一些代码从 Vapor 3 迁移到 Vapor 4。我已经阅读了 Vapor 4文档中有关此特定模式的文档,我想我对它的大部分了解。
然而,我没有得到的一件事是在Application扩展中设置存储库工厂的方式。文档中的示例显示了这一点:
extension Application {
private struct UserRepositoryKey: StorageKey {
typealias Value = UserRepositoryFactory
}
var users: UserRepositoryFactory {
get {
self.storage[UserRepositoryKey.self] ?? .init()
}
set {
self.storage[UserRepositoryKey.self] = newValue
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我正确阅读了 getter 方法(我可能不是 - 我离 Swift 专家还很远),UserRepositoryFactory将创建一个新的结构实例并在app.users引用时返回。但是,当时似乎没有self.storage[UserRepositoryKey.self]以任何方式更改的内容。因此,如果我碰巧app.users连续访问两次,我会得到 2 个不同的实例返回给我,并且self.storage[UserRepositoryKey.self]将保持设置为nil.
按照文档中的其余示例代码,它似乎定义make了工厂在配置应用程序时将使用的函数,如下所示:
app.users.use { req in
DatabaseUserRepository(database: req.db)
}
Run Code Online (Sandbox Code Playgroud)
这里似乎app.users.use会得到一个新的工厂实例并调用它的use函数来make为该实例设置适当的方法。
后来,当我去处理一个请求时,我使用了request.users这个Request扩展定义的方法:
extension Request {
var users: UserRepository {
self.application.users.make!(self)
}
}
Run Code Online (Sandbox Code Playgroud)
这里似乎self.application.users.make会在由self.application.users. 因此,它不会应用之前在配置应用程序时设置的工厂 make 方法。
那么我在这里错过了什么?
看起来文档有点过时了。您可以查看视图或客户端是如何完成的,但是您需要在某个地方调用initialize()来设置存储库。这是我的工作存储库的样子:
import Vapor
extension Application {
struct Repositories {
struct Provider {
let run: (Application) -> ()
public init(_ run: @escaping (Application) -> ()) {
self.run = run
}
}
final class Storage {
var makeRepository: ((Application) -> APIRepository)?
init() { }
}
struct Key: StorageKey {
typealias Value = Storage
}
let application: Application
var repository: APIRepository {
guard let makeRepository = self.storage.makeRepository else {
fatalError("No repository configured. Configure with app.repositories.use(...)")
}
return makeRepository(self.application)
}
func use(_ provider: Provider) {
provider.run(self.application)
}
func use(_ makeRepository: @escaping (Application) -> APIRepository) {
self.storage.makeRepository = makeRepository
}
func initialize() {
self.application.storage[Key.self] = .init()
}
private var storage: Storage {
if self.application.storage[Key.self] == nil {
self.initialize()
}
return self.application.storage[Key.self]!
}
}
var repositories: Repositories {
.init(application: self)
}
}
Run Code Online (Sandbox Code Playgroud)
第一次使用时会自动初始化。请注意,这APIRepository是我的存储库使用的协议。FluentRepository是该协议的 Fluent 实现。然后像你一样,我有一个关于 Request 的扩展,可以在请求处理程序中使用它:
extension Request {
var repository: APIRepository {
self.application.repositories.repository.for(self)
}
}
Run Code Online (Sandbox Code Playgroud)
最后,您需要将其配置为使用正确的存储库。所以在我的configure.swift中我有:
app.repositories.use { application in
FluentRepository(database: application.db)
}
Run Code Online (Sandbox Code Playgroud)
在测试中,我可以将其切换为不接触数据库的内存存储库:
application.repositories.use { _ in
return inMemoryRepository
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
251 次 |
| 最近记录: |