Files
data-raft/Sources/DataRaft/Protocols/VersionStorage.swift
2025-11-09 15:58:05 +02:00

123 lines
4.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
import DataLiteCore
/// A type that defines how a database schema version is stored and retrieved.
///
/// ## Overview
///
/// This protocol separates the concept of version representation from its persistence mechanism,
/// allowing flexible implementations that store version values in different formats or locations.
///
/// The associated ``Version`` type specifies how the version is represented (for example, as an
/// integer, a semantic string, or a structured object), while the conforming type defines how that
/// version is persisted.
///
/// ## Usage
///
/// Implement this type to define a custom strategy for schema version tracking:
/// - Store an integer version in SQLites `user_version` field.
/// - Store a string in a dedicated metadata table.
/// - Store structured data in a JSON column.
///
/// The example below shows an implementation that stores the version string in a `schema_version`
/// table:
///
/// ```swift
/// final class StringVersionStorage: VersionStorage {
/// typealias Version = String
///
/// func prepare(_ connection: ConnectionProtocol) throws {
/// let script = """
/// CREATE TABLE IF NOT EXISTS schema_version (
/// version TEXT NOT NULL
/// );
///
/// INSERT INTO schema_version (version)
/// SELECT '0.0.0'
/// WHERE NOT EXISTS (SELECT 1 FROM schema_version);
/// """
/// try connection.execute(sql: script)
/// }
///
/// func getVersion(_ connection: ConnectionProtocol) throws -> Version {
/// let query = "SELECT version FROM schema_version LIMIT 1"
/// let stmt = try connection.prepare(sql: query)
/// guard try stmt.step(), let value: Version = stmt.columnValue(at: 0) else {
/// throw DatabaseError.message("Missing version in schema_version table.")
/// }
/// return value
/// }
///
/// func setVersion(_ connection: ConnectionProtocol, _ version: Version) throws {
/// let query = "UPDATE schema_version SET version = ?"
/// let stmt = try connection.prepare(sql: query)
/// try stmt.bind(version, at: 0)
/// try stmt.step()
/// }
/// }
/// ```
///
/// ## Topics
///
/// ### Associated Types
///
/// - ``Version``
///
/// ### Instance Methods
///
/// - ``prepare(_:)``
/// - ``getVersion(_:)``
/// - ``setVersion(_:_:)``
public protocol VersionStorage {
/// The type representing the database schema version.
associatedtype Version: VersionRepresentable
/// Creates a new instance of the version storage.
init()
/// Prepares the storage mechanism for tracking the schema version.
///
/// Called before any version operations. Use this method to create required tables or metadata
/// structures for version management.
///
/// - Important: Executed within an active migration transaction. Do not issue `BEGIN` or
/// `COMMIT` manually. If this method throws an error, the migration process will be aborted
/// and rolled back.
///
/// - Parameter connection: The database connection used for schema preparation.
/// - Throws: An error if preparation fails.
func prepare(_ connection: ConnectionProtocol) throws
/// Returns the current schema version stored in the database.
///
/// Must return a valid version previously stored by the migration system.
///
/// - Important: Executed within an active migration transaction. Do not issue `BEGIN` or
/// `COMMIT` manually. If this method throws an error, the migration process will be aborted
/// and rolled back.
///
/// - Parameter connection: The database connection used to fetch the version.
/// - Returns: The version currently stored in the database.
/// - Throws: An error if reading fails or the version is missing.
func getVersion(_ connection: ConnectionProtocol) throws -> Version
/// Stores the given version as the current schema version.
///
/// Called at the end of the migration process to persist the final schema version after all
/// migration steps complete successfully.
///
/// - Important: Executed within an active migration transaction. Do not issue `BEGIN` or
/// `COMMIT` manually. If this method throws an error, the migration process will be aborted
/// and rolled back.
///
/// - Parameters:
/// - connection: The database connection used to write the version.
/// - version: The version to store.
/// - Throws: An error if writing fails.
func setVersion(_ connection: ConnectionProtocol, _ version: Version) throws
}
public extension VersionStorage {
func prepare(_ connection: ConnectionProtocol) throws {}
}