Skip to content

Commit 4461fd4

Browse files
committed
Added dynamic member lookup for embeded structs
1 parent 878875e commit 4461fd4

5 files changed

Lines changed: 66 additions & 5 deletions

File tree

Sources/Compiler/Gen/SwiftLanguage.swift

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ public struct SwiftLanguage: Language {
202202

203203
return DeclSyntax(variable)
204204
}
205-
205+
206206
/// Generates the expression to initialize the query.
207207
///
208208
/// ```swift
@@ -416,7 +416,7 @@ public struct SwiftLanguage: Language {
416416
"""
417417
}
418418
}
419-
419+
420420
private static func declaration(
421421
for model: GeneratedModel,
422422
isOutput: Bool,
@@ -435,7 +435,20 @@ public struct SwiftLanguage: Language {
435435
}
436436
}
437437

438+
let dynamicLookupTables = model.fields.values.compactMap { value -> (String, GeneratedModel)? in
439+
guard case let .model(model) = value.type else { return nil }
440+
return (value.name, model)
441+
}
442+
443+
let addDynamicLookup = isOutput && !dynamicLookupTables.isEmpty && model.fields.count > 1
444+
438445
let strct = StructDeclSyntax(
446+
attributes: AttributeListSyntax {
447+
if addDynamicLookup {
448+
let attr: AttributeSyntax = "@dynamicMemberLookup"
449+
attr.with(\.trailingTrivia, .newline)
450+
}
451+
},
439452
name: TokenSyntax.identifier(model.name),
440453
inheritanceClause: inheretance
441454
) {
@@ -447,11 +460,54 @@ public struct SwiftLanguage: Language {
447460
rowDecodableInit(for: model)
448461
memberwiseInit(for: model)
449462
}
463+
464+
if addDynamicLookup {
465+
for (fieldName, table) in dynamicLookupTables {
466+
dynamicMemberLookup(fieldName: fieldName, typeName: table.name)
467+
}
468+
}
450469
}
451470

452471
return DeclSyntax(strct)
453472
}
454473

474+
private static func dynamicMemberLookup(
475+
fieldName: String,
476+
typeName: String
477+
) -> SubscriptDeclSyntax {
478+
return SubscriptDeclSyntax(
479+
subscriptKeyword: TokenSyntax.keyword(.subscript)
480+
.with(\.trailingTrivia, .spaces(0)),
481+
genericParameterClause: GenericParameterClauseSyntax {
482+
GenericParameterSyntax(name: "Value")
483+
},
484+
parameterClause: FunctionParameterClauseSyntax(
485+
parameters: [
486+
FunctionParameterSyntax(
487+
firstName: "dynamicMember",
488+
secondName: "dynamicMember",
489+
type: IdentifierTypeSyntax(name: "KeyPath<\(raw: typeName), Value>"),
490+
trailingComma: nil
491+
)
492+
]
493+
),
494+
returnClause: ReturnClauseSyntax(type: IdentifierTypeSyntax(name: "Value")),
495+
accessorBlock: AccessorBlockSyntax(accessors: .getter(CodeBlockItemListSyntax {
496+
SubscriptCallExprSyntax(
497+
calledExpression: DeclReferenceExprSyntax(baseName: TokenSyntax.identifier(fieldName)),
498+
arguments: LabeledExprListSyntax {
499+
LabeledExprSyntax(
500+
label: "keyPath",
501+
colon: TokenSyntax.colonToken(),
502+
expression: DeclReferenceExprSyntax(baseName: "dynamicMember"),
503+
trailingComma: nil
504+
)
505+
}
506+
)
507+
}))
508+
)
509+
}
510+
455511
private static func rowDecodableInit(
456512
for model: GeneratedModel
457513
) -> InitializerDeclSyntax {

Sources/Compiler/Project.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import Foundation
99

10+
/// Small object to make interacting with the overall project structure easier.
1011
public struct Project {
1112
public let url: URL
1213
public let migrationsDirectory: URL
@@ -24,6 +25,10 @@ public struct Project {
2425
self.queriesDirectory = url.appendingPathComponent("Queries")
2526
}
2627

28+
public static func inWorkingDir() -> Project {
29+
Project(url: URL(fileURLWithPath: FileManager.default.currentDirectoryPath))
30+
}
31+
2732
public var doesMigrationsExist: Bool {
2833
fileSystem.exists(at: migrationsDirectory)
2934
}

Sources/FeatherCLI/InitCommand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct InitCommand: ParsableCommand {
1313
static let configuration = CommandConfiguration(commandName: "init")
1414

1515
func run() throws {
16-
let project = Project(url: URL(fileURLWithPath: FileManager.default.currentDirectoryPath))
16+
let project = Project.inWorkingDir()
1717
try project.setup()
1818
try project.addMigration()
1919
}

Sources/FeatherCLI/MigrateCommand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct MigrateCommand: ParsableCommand {
1919
static let configuration = CommandConfiguration(commandName: "add")
2020

2121
func run() throws {
22-
let project = Project(url: URL(fileURLWithPath: FileManager.default.currentDirectoryPath))
22+
let project = Project.inWorkingDir()
2323

2424
guard project.doesMigrationsExist else {
2525
throw FeatherError.sourcesNotFound

Sources/FeatherCLI/QueriesCommand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct QueriesCommand: ParsableCommand {
2121
@Argument var name: String
2222

2323
func run() throws {
24-
let project = Project(url: URL(fileURLWithPath: FileManager.default.currentDirectoryPath))
24+
let project = Project.inWorkingDir()
2525

2626
guard project.doesQueriesExist else {
2727
throw FeatherError.sourcesNotFound

0 commit comments

Comments
 (0)