Initial commit.
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import FluentKit
|
||||
|
||||
/// Creates and drops the `example_records` table backing ``ExampleRecord``.
|
||||
///
|
||||
/// Reference scaffolding paired with ``ExampleRecord``; replace it with the first real migration once a
|
||||
/// domain model is defined. Migrations are append-only in production — add a new migration to alter the
|
||||
/// schema rather than editing one that has already run.
|
||||
struct CreateExampleRecord: AsyncMigration {
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Creates the `example_records` table with an `id` primary key and a required `name` column.
|
||||
/// - Parameter database: the database the schema change is applied to.
|
||||
func prepare(on database: Database) async throws {
|
||||
try await database.schema(ExampleRecord.schema)
|
||||
.id()
|
||||
.field("name", .string, .required)
|
||||
.create()
|
||||
}
|
||||
|
||||
/// Drops the `example_records` table, reverting ``prepare(on:)``.
|
||||
/// - Parameter database: the database the schema change is applied to.
|
||||
func revert(on database: Database) async throws {
|
||||
try await database.schema(ExampleRecord.schema)
|
||||
.delete()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import FluentKit
|
||||
import Foundation
|
||||
|
||||
/// A FluentKit model of a single `example_records` row.
|
||||
///
|
||||
/// This is reference scaffolding: it demonstrates the model → migration → repository pattern the rest of
|
||||
/// the package is built around, and is what the tests exercise. Replace it with the first real domain model
|
||||
/// (paired with its own migration and repository) once one is defined.
|
||||
///
|
||||
/// FluentKit models are mutable reference types whose property wrappers are not `Sendable`; the model never
|
||||
/// crosses a concurrency boundary (repositories map it to a `Sendable` snapshot before returning), so the
|
||||
/// conformance is declared `@unchecked Sendable`.
|
||||
final class ExampleRecord: Model, @unchecked Sendable {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The name of the backing table.
|
||||
static let schema = "example_records"
|
||||
|
||||
/// The row's primary key, assigned on first save.
|
||||
@ID(key: .id)
|
||||
var id: UUID?
|
||||
|
||||
/// The row's name column.
|
||||
@Field(key: "name")
|
||||
var name: String
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Creates an empty record, as required by FluentKit to hydrate query results.
|
||||
init() {}
|
||||
|
||||
/// Creates a record with the given values.
|
||||
/// - Parameters:
|
||||
/// - id: the primary key, or `nil` to have one assigned on save.
|
||||
/// - name: the value of the name column.
|
||||
init(
|
||||
id: UUID? = nil,
|
||||
name: String
|
||||
) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import FluentKit
|
||||
import Foundation
|
||||
import HummingbirdFluent
|
||||
|
||||
/// A `Sendable` snapshot of an ``ExampleRecord``, safe to return across concurrency boundaries.
|
||||
///
|
||||
/// Repositories return these value-type snapshots rather than FluentKit models, which are mutable reference
|
||||
/// types that must not escape the database's execution context.
|
||||
public struct Example: Sendable, Equatable {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The record's primary key, or `nil` if it has never been saved.
|
||||
public let id: UUID?
|
||||
/// The record's name.
|
||||
public let name: String
|
||||
|
||||
}
|
||||
|
||||
/// Reads and writes ``ExampleRecord`` rows through the default database.
|
||||
///
|
||||
/// This is the shape every real repository takes: it holds the `Sendable` `Fluent` service, resolves the
|
||||
/// default database per call, and maps FluentKit models to `Sendable` snapshots before returning — so no
|
||||
/// model ever escapes across an async boundary. It is reference scaffolding paired with ``ExampleRecord``;
|
||||
/// replace it with the first real repository once a domain model is defined.
|
||||
public struct ExampleRepository: Sendable {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The service providing the default database the repository reads and writes through.
|
||||
private let fluent: Fluent
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Creates a repository backed by the given `Fluent` service.
|
||||
/// - Parameter fluent: the service whose default database the repository operates on.
|
||||
public init(fluent: Fluent) {
|
||||
self.fluent = fluent
|
||||
}
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Inserts a record with the given name.
|
||||
/// - Parameter name: the name of the record to insert.
|
||||
/// - Returns: a `Sendable` snapshot of the inserted record, including its assigned identifier.
|
||||
public func create(name: String) async throws -> Example {
|
||||
let record = ExampleRecord(name: name)
|
||||
|
||||
try await record.save(on: fluent.db())
|
||||
|
||||
return Example(id: record.id, name: record.name)
|
||||
}
|
||||
|
||||
/// Fetches every record, ordered by name.
|
||||
/// - Returns: a `Sendable` snapshot of each record, sorted by name.
|
||||
public func all() async throws -> [Example] {
|
||||
try await ExampleRecord.query(on: fluent.db())
|
||||
.sort(\.$name)
|
||||
.all()
|
||||
.map { Example(id: $0.id, name: $0.name) }
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user