139 lines
4.7 KiB
Swift
139 lines
4.7 KiB
Swift
import Foundation
|
|
import DataLiteCoder
|
|
|
|
/// A database service that provides model encoding and decoding support.
|
|
///
|
|
/// ## Overview
|
|
///
|
|
/// `ModelDatabaseService` extends ``DatabaseService`` by integrating `RowEncoder` and `RowDecoder`
|
|
/// to simplify model-based interactions with the database. Subclasses can encode Swift types into
|
|
/// SQLite rows and decode query results back into strongly typed models.
|
|
///
|
|
/// This enables a clean, type-safe persistence layer for applications that use Codable or custom
|
|
/// encodable/decodable types.
|
|
///
|
|
/// `ModelDatabaseService` serves as a foundation for higher-level model repositories and services.
|
|
/// It inherits all transactional and thread-safe behavior from ``DatabaseService`` while adding
|
|
/// automatic model serialization.
|
|
///
|
|
/// ## Usage
|
|
///
|
|
/// ```swift
|
|
/// struct User: Codable {
|
|
/// let id: Int
|
|
/// let name: String
|
|
/// }
|
|
///
|
|
/// final class UserService: ModelDatabaseService, @unchecked Sendable {
|
|
/// func fetchUser() throws -> User? {
|
|
/// try perform(in: .deferred) { connection in
|
|
/// let stmt = try connection.prepare(sql: "SELECT * FROM users")
|
|
/// guard try stmt.step(), let row = stmt.currentRow() else {
|
|
/// return nil
|
|
/// }
|
|
/// return try decoder.decode(User.self, from: row)
|
|
/// }
|
|
/// }
|
|
///
|
|
/// func insertUser(_ user: User) throws {
|
|
/// try perform(in: .immediate) { connection in
|
|
/// let row = try encoder.encode(user)
|
|
/// let columns = row.columns.joined(separator: ", ")
|
|
/// let placeholders = row.namedParameters.joined(separator: ", ")
|
|
/// let sql = "INSERT INTO users (\(columns)) VALUES (\(placeholders))"
|
|
/// let stmt = try connection.prepare(sql: sql)
|
|
/// try stmt.execute([row])
|
|
/// }
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// ## Topics
|
|
///
|
|
/// ### Properties
|
|
///
|
|
/// - ``encoder``
|
|
/// - ``decoder``
|
|
///
|
|
/// ### Initializers
|
|
///
|
|
/// - ``init(provider:config:queue:center:encoder:decoder:)``
|
|
/// - ``init(provider:config:queue:)``
|
|
/// - ``init(connection:config:queue:)``
|
|
open class ModelDatabaseService: DatabaseService, @unchecked Sendable {
|
|
// MARK: - Properties
|
|
|
|
/// The encoder used to serialize models into row representations.
|
|
public let encoder: RowEncoder
|
|
|
|
/// The decoder used to deserialize database rows into model instances.
|
|
public let decoder: RowDecoder
|
|
|
|
// MARK: - Inits
|
|
|
|
/// Creates a model-aware database service.
|
|
///
|
|
/// - Parameters:
|
|
/// - provider: A closure that returns a new database connection.
|
|
/// - config: Optional configuration for the connection.
|
|
/// - queue: The dispatch queue used for serializing database operations.
|
|
/// - center: The notification center used for database events. Defaults to `.databaseCenter`.
|
|
/// - encoder: The encoder for converting models into SQLite rows.
|
|
/// - decoder: The decoder for converting rows back into model instances.
|
|
public init(
|
|
provider: @escaping ConnectionProvider,
|
|
config: ConnectionConfig? = nil,
|
|
queue: DispatchQueue? = nil,
|
|
center: NotificationCenter = .databaseCenter,
|
|
encoder: RowEncoder,
|
|
decoder: RowDecoder
|
|
) {
|
|
self.encoder = encoder
|
|
self.decoder = decoder
|
|
super.init(
|
|
provider: provider,
|
|
config: config,
|
|
queue: queue,
|
|
center: center
|
|
)
|
|
}
|
|
|
|
/// Creates a model-aware database service using default encoder and decoder instances.
|
|
///
|
|
/// - Parameters:
|
|
/// - provider: A closure that returns a new database connection.
|
|
/// - config: Optional configuration for the connection.
|
|
/// - queue: The dispatch queue used for serializing database operations.
|
|
public required init(
|
|
provider: @escaping ConnectionProvider,
|
|
config: ConnectionConfig? = nil,
|
|
queue: DispatchQueue? = nil
|
|
) {
|
|
self.encoder = .init()
|
|
self.decoder = .init()
|
|
super.init(
|
|
provider: provider,
|
|
config: config,
|
|
queue: queue
|
|
)
|
|
}
|
|
|
|
/// Creates a model-aware database service from a connection autoclosure.
|
|
///
|
|
/// - Parameters:
|
|
/// - provider: A connection autoclosure that returns a database connection.
|
|
/// - config: Optional configuration for the connection.
|
|
/// - queue: The dispatch queue used for serializing database operations.
|
|
public required convenience init(
|
|
connection provider: @escaping @autoclosure ConnectionProvider,
|
|
config: ConnectionConfig? = nil,
|
|
queue: DispatchQueue? = nil
|
|
) {
|
|
self.init(
|
|
provider: provider,
|
|
config: config,
|
|
queue: queue
|
|
)
|
|
}
|
|
}
|