Skip to content

Commit 70c07e1

Browse files
Update eager loading and add optional Parameter function
1 parent 8386c47 commit 70c07e1

File tree

3 files changed

+38
-19
lines changed

3 files changed

+38
-19
lines changed

Sources/Alchemy/HTTP/Request/Request.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ public final class Request: RequestInspector {
4646
self.parameters = parameters
4747
}
4848

49+
public func parameter<L: LosslessStringConvertible>(_ key: String, as: L.Type = L.self) -> L? {
50+
parameters.first(where: { $0.key == key }).map { L($0.value) } ?? nil
51+
}
52+
4953
/// Returns the first parameter for the given key, if there is one.
5054
///
5155
/// Use this to fetch any parameters from the path.

Sources/Alchemy/SQL/Rune/Model/Model+PrimaryKey.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Foundation
33
/// Represents a type that may be a primary key in a database. Out of
44
/// the box `UUID`, `String` and `Int` are supported but you can
55
/// easily support your own by conforming to this protocol.
6-
public protocol PrimaryKey: Hashable, SQLValueConvertible, Codable {
6+
public protocol PrimaryKey: Hashable, SQLValueConvertible, Codable, LosslessStringConvertible {
77
/// Initialize this value from an `SQLValue`.
88
///
99
/// - Throws: If there is an error decoding this type from the

Sources/Alchemy/SQL/Rune/Model/ModelQuery+EagerLoad.swift

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
11
extension ModelQuery {
2-
/// A closure for defining any nested eager loading when loading a
3-
/// relationship on this `Model`.
4-
///
5-
/// "Eager loading" refers to loading a model at the other end of
6-
/// a relationship of this queried model. Nested eager loads
7-
/// refers to loading a model from a relationship on that
8-
/// _other_ model.
9-
public typealias NestedQuery<R: Model> = (ModelQuery<R>) -> ModelQuery<R>
10-
112
/// A tuple of models and the SQLRow that they were loaded from.
123
typealias ModelRow = (model: M, row: SQLRow)
134

@@ -100,6 +91,15 @@ extension ModelQuery {
10091
}
10192
}
10293

94+
/// A closure for defining any nested eager loading when loading a
95+
/// relationship on this `Model`.
96+
///
97+
/// "Eager loading" refers to loading a model at the other end of
98+
/// a relationship of this queried model. Nested eager loads
99+
/// refers to loading a model from a relationship on that
100+
/// _other_ model.
101+
public typealias NestedQuery<R: Model> = (ModelQuery<R>) -> ModelQuery<R>
102+
103103
extension RelationshipMapping {
104104
fileprivate func load<M: Model>(_ values: [SQLRow], database: Database) throws -> ModelQuery<M> {
105105
var query = M.query(database: database)
@@ -132,26 +132,41 @@ extension Array where Element: Hashable {
132132
}
133133
}
134134

135-
136135
// MARK: - Additional Eager Load convience functions
137136

138137
extension Model {
139-
public func with<R: Relationship>(db: Database = DB, _ relationship: KeyPath<Self, R>) async throws -> Self where R.From == Self {
140-
try await sync(db: db) { $0.with(relationship) }
138+
public func with<R: Relationship>(
139+
db: Database = DB,
140+
_ relationship: KeyPath<Self, R>,
141+
nested: @escaping NestedQuery<R.To.Value> = { $0 }
142+
) async throws -> Self where R.From == Self {
143+
try await sync(db: db) { $0.with(relationship, nested: nested) }
141144
}
142145

143-
public func fetch<R: Relationship>(db: Database = DB, _ relationship: KeyPath<Self, R>) async throws -> R.Wrapped where R.From == Self {
144-
try await sync(db: db) { $0.with(relationship) }[keyPath: relationship].wrappedValue
146+
public func fetch<R: Relationship>(
147+
db: Database = DB,
148+
_ relationship: KeyPath<Self, R>,
149+
nested: @escaping NestedQuery<R.To.Value> = { $0 }
150+
) async throws -> R.Wrapped where R.From == Self {
151+
try await sync(db: db) { $0.with(relationship, nested: nested) }[keyPath: relationship].wrappedValue
145152
}
146153
}
147154

148155
extension Array where Element: Model {
149-
public func with<R: Relationship>(db: Database = DB, _ relationship: KeyPath<Element, R>) async throws -> Self where R.From == Element {
150-
try await syncAll(db: db) { $0.with(relationship) }
156+
public func with<R: Relationship>(
157+
db: Database = DB,
158+
_ relationship: KeyPath<Element, R>,
159+
nested: @escaping NestedQuery<R.To.Value> = { $0 }
160+
) async throws -> Self where R.From == Element {
161+
try await syncAll(db: db) { $0.with(relationship, nested: nested) }
151162
}
152163

153-
public func fetch<R: Relationship>(db: Database = DB, _ relationship: KeyPath<Element, R>) async throws -> [R.Wrapped] where R.From == Element {
154-
try await syncAll(db: db) { $0.with(relationship) }
164+
public func fetch<R: Relationship>(
165+
db: Database = DB,
166+
_ relationship: KeyPath<Element, R>,
167+
nested: @escaping NestedQuery<R.To.Value> = { $0 }
168+
) async throws -> [R.Wrapped] where R.From == Element {
169+
try await syncAll(db: db) { $0.with(relationship, nested: nested) }
155170
.map { $0[keyPath: relationship].wrappedValue }
156171
}
157172
}

0 commit comments

Comments
 (0)