100 lines
3.5 KiB
Swift
100 lines
3.5 KiB
Swift
import FluentPostgresDriver
|
|
import FluentSQLiteDriver
|
|
import HummingbirdFluent
|
|
import Logging
|
|
import PostgresNIO
|
|
|
|
/// A factory building the `Fluent` service the application persists through.
|
|
///
|
|
/// Built once around the driver the executable picks at startup and called as a function to produce the configured service: `let fluent = service()`.
|
|
public struct Service: Sendable {
|
|
|
|
// MARK: Enumerations
|
|
|
|
/// The persistence backend resolved at construction, with the PostgreSQL TLS mode already built.
|
|
private enum Backend {
|
|
case postgres(Configuration, PostgresConnection.Configuration.TLS)
|
|
case inMemory
|
|
}
|
|
|
|
// MARK: Properties
|
|
|
|
/// The resolved persistence backend to register.
|
|
private let backend: Backend
|
|
|
|
/// The logger the database emits through.
|
|
private let logger: Logger
|
|
|
|
// MARK: Initializers
|
|
|
|
/// Creates a factory for a `Fluent` service backed by the given driver.
|
|
///
|
|
/// The TLS context for the PostgreSQL backend is built here, once — the factory holds only resolved configuration, so producing the
|
|
/// service afterwards cannot fail.
|
|
/// - Parameters:
|
|
/// - driver: the persistence backend to register.
|
|
/// - logger: the logger the database emits through.
|
|
/// - Throws: an error when the TLS context for the PostgreSQL backend cannot be built.
|
|
public init(
|
|
driver: Driver,
|
|
logger: Logger
|
|
) throws {
|
|
switch driver {
|
|
case .postgres(let configuration):
|
|
self.backend = .postgres(
|
|
configuration,
|
|
try configuration.tls.postgresTLS()
|
|
)
|
|
case .inMemory:
|
|
self.backend = .inMemory
|
|
}
|
|
|
|
self.logger = logger
|
|
}
|
|
|
|
// MARK: Methods
|
|
|
|
/// Builds a `Fluent` service configured for the driver.
|
|
///
|
|
/// The selected backend is registered as the *default* database, so repositories resolve it with a plain `fluent.db()` and stay agnostic of which
|
|
/// driver is in use. The returned service is not yet running; add it to the application's service group (`app.addServices(_:)`) so it starts and shuts
|
|
/// its connection pool down alongside the server.
|
|
/// - Returns: the configured `Fluent` service, ready to be added to the service group.
|
|
public func callAsFunction() -> Fluent {
|
|
let fluent = Fluent(
|
|
logger: logger
|
|
)
|
|
|
|
switch backend {
|
|
case .postgres(let configuration, let tls):
|
|
fluent.databases.use(
|
|
.postgres(
|
|
configuration: .init(
|
|
hostname: configuration.host,
|
|
port: configuration.port,
|
|
username: configuration.username,
|
|
password: configuration.password,
|
|
database: configuration.name,
|
|
tls: tls
|
|
),
|
|
maxConnectionsPerEventLoop: configuration.maxConnectionsPerEventLoop,
|
|
connectionPoolTimeout: .init(configuration.poolTimeout)
|
|
),
|
|
as: .psql,
|
|
isDefault: true
|
|
)
|
|
case .inMemory:
|
|
// A single connection keeps every query pointed at the same in-memory store, rather than each pooled
|
|
// connection getting its own private database.
|
|
fluent.databases.use(
|
|
.sqlite(.memory, maxConnectionsPerEventLoop: 1),
|
|
as: .sqlite,
|
|
isDefault: true
|
|
)
|
|
}
|
|
|
|
return fluent
|
|
}
|
|
|
|
}
|